diff --git a/BUILD.gn b/BUILD.gn index 5728f427..8f84ca3 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -547,6 +547,7 @@ "//sandbox/win:sbox_validation_tests", "//testing/gtest:gtest_main", "//third_party/pdfium/samples:pdfium_diff", + "//third_party/tcmalloc:addr2line-pdb", "//tools/win/chromeexts:chromeexts", ] deps -= [
diff --git a/DEPS b/DEPS index 41f80bc..c5e93403 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '0b83319b7f301145b7fc89d7096ddcea91d4a56b', + 'skia_revision': 'b66fa526b882f2472d731b42cba65fe05cea4268', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '0029fb25b9b69f2e4465164282eb1040b60437dd', + 'pdfium_revision': 'cfdb5fdd12d47136ad1db9a67fc598a71f6757ff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '76b86f523bce70142abb163469b0973c0b20e9fb', + 'catapult_revision': 'faf60eb37f8b9828eddb30c8397b333eb1d89204', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index ee6ab23..699a62b 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -340,7 +340,6 @@ _ANDROID_SPECIFIC_PYDEPS_FILES = [ 'build/android/test_runner.pydeps', - 'build/android/test_wrapper/logdog_wrapper.pydeps', 'net/tools/testserver/testserver.pydeps', ]
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java index d00a3da9..d9f61fa 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java
@@ -10,6 +10,7 @@ import org.chromium.android_webview.AwContents; import org.chromium.android_webview.permission.AwPermissionRequest; import org.chromium.android_webview.permission.Resource; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import java.util.concurrent.Callable; @@ -104,7 +105,8 @@ } @Feature({"AndroidWebView"}) - @SmallTest + @DisabledTest + // crbug/701916 public void testSupportWidevineKeySystem() throws Throwable { assertEquals( getPlatformKeySystemExpectations(), isKeySystemSupported("com.widevine.alpha")); @@ -117,7 +119,8 @@ } @Feature({"AndroidWebView"}) - @SmallTest + @DisabledTest + // crbug/701916 public void testSupportPlatformKeySystem() throws Throwable { assertEquals(getPlatformKeySystemExpectations(), isKeySystemSupported("x-com.oem.test-keysystem"));
diff --git a/ash/common/shelf/shelf_controller.cc b/ash/common/shelf/shelf_controller.cc index 7137d23..fa47593 100644 --- a/ash/common/shelf/shelf_controller.cc +++ b/ash/common/shelf/shelf_controller.cc
@@ -93,9 +93,6 @@ void ShelfController::SetAlignment(ShelfAlignment alignment, int64_t display_id) { - if (!ash::WmShelf::CanChangeShelfAlignment()) - return; - WmShelf* shelf = GetShelfForDisplay(display_id); // TODO(jamescook): The initialization check should not be necessary, but // otherwise this wrongly tries to set the alignment on a secondary display
diff --git a/ash/sticky_keys/sticky_keys_controller.cc b/ash/sticky_keys/sticky_keys_controller.cc index d3257a8a..29706f8f 100644 --- a/ash/sticky_keys/sticky_keys_controller.cc +++ b/ash/sticky_keys/sticky_keys_controller.cc
@@ -295,7 +295,7 @@ DCHECK(new_event); if (*new_event) return 1; - new_event->reset(modifier_up_event_.release()); + *new_event = std::move(modifier_up_event_); return 0; }
diff --git a/ash/test/shelf_button_pressed_metric_tracker_test_api.cc b/ash/test/shelf_button_pressed_metric_tracker_test_api.cc index 85afeb93..6deddd65 100644 --- a/ash/test/shelf_button_pressed_metric_tracker_test_api.cc +++ b/ash/test/shelf_button_pressed_metric_tracker_test_api.cc
@@ -19,7 +19,7 @@ void ShelfButtonPressedMetricTrackerTestAPI::SetTickClock( std::unique_ptr<base::TickClock> tick_clock) { - shelf_button_pressed_metric_tracker_->tick_clock_.reset(tick_clock.release()); + shelf_button_pressed_metric_tracker_->tick_clock_ = std::move(tick_clock); } } // namespace test
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h index a3ff90e..c720a50 100644 --- a/base/allocator/partition_allocator/partition_alloc.h +++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -60,6 +60,7 @@ // - Better freelist masking function to guarantee fault on 32-bit. #include <limits.h> +#include <string.h> #include "base/allocator/partition_allocator/page_allocator.h" #include "base/allocator/partition_allocator/spin_lock.h"
diff --git a/base/native_library.h b/base/native_library.h index 02eae1d..e2b9ca7e 100644 --- a/base/native_library.h +++ b/base/native_library.h
@@ -91,16 +91,6 @@ const NativeLibraryOptions& options, NativeLibraryLoadError* error); -#if defined(OS_WIN) -// Loads a native library from disk. Release it with UnloadNativeLibrary when -// you're done. -// This function retrieves the LoadLibrary function exported from kernel32.dll -// and calls it instead of directly calling the LoadLibrary function via the -// import table. -BASE_EXPORT NativeLibrary LoadNativeLibraryDynamically( - const FilePath& library_path); -#endif // OS_WIN - // Unloads a native library. BASE_EXPORT void UnloadNativeLibrary(NativeLibrary library);
diff --git a/base/native_library_win.cc b/base/native_library_win.cc index 64c7380..68ff3d1f 100644 --- a/base/native_library_win.cc +++ b/base/native_library_win.cc
@@ -7,6 +7,7 @@ #include <windows.h> #include "base/files/file_util.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -14,16 +15,108 @@ namespace base { -typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); +using AddDllDirectory = HMODULE (*)(PCWSTR new_directory); namespace { +// This enum is used to back an UMA histogram, and should therefore be treated +// as append-only. +enum LoadLibraryResult { + // LoadLibraryExW API/flags are available and the call succeeds. + SUCCEED = 0, + // LoadLibraryExW API/flags are availabe to use but the call fails, then + // LoadLibraryW is used and succeeds. + FAIL_AND_SUCCEED, + // LoadLibraryExW API/flags are availabe to use but the call fails, then + // LoadLibraryW is used but fails as well. + FAIL_AND_FAIL, + // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used + // and succeeds. + UNAVAILABLE_AND_SUCCEED, + // LoadLibraryExW API/flags are unavailabe to use, then LoadLibraryW is used + // but fails. + UNAVAILABLE_AND_FAIL, + // Add new items before this one, always keep this one at the end. + END +}; + +// A helper method to log library loading result to UMA. +void LogLibrarayLoadResultToUMA(LoadLibraryResult result) { + UMA_HISTOGRAM_ENUMERATION("LibraryLoader.LoadNativeLibraryWindows", result, + LoadLibraryResult::END); +} + +// A helper method to check if AddDllDirectory method is available, thus +// LOAD_LIBRARY_SEARCH_* flags are available on systems. +bool AreSearchFlagsAvailable() { + // The LOAD_LIBRARY_SEARCH_* flags are available on systems that have + // KB2533623 installed. To determine whether the flags are available, use + // GetProcAddress to get the address of the AddDllDirectory, + // RemoveDllDirectory, or SetDefaultDllDirectories function. If GetProcAddress + // succeeds, the LOAD_LIBRARY_SEARCH_* flags can be used with LoadLibraryEx. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx + // The LOAD_LIBRARY_SEARCH_* flags are used in the LoadNativeLibraryHelper + // method. + auto add_dll_dir_func = reinterpret_cast<AddDllDirectory>( + GetProcAddress(GetModuleHandle(L"kernel32.dll"), "AddDllDirectory")); + return !!add_dll_dir_func; +} + +// A helper method to encode the library loading result to enum +// LoadLibraryResult. +LoadLibraryResult GetLoadLibraryResult(bool are_search_flags_available, + bool has_load_library_succeeded) { + LoadLibraryResult result; + if (are_search_flags_available) { + if (has_load_library_succeeded) + result = LoadLibraryResult::FAIL_AND_SUCCEED; + else + result = LoadLibraryResult::FAIL_AND_FAIL; + } else if (has_load_library_succeeded) { + result = LoadLibraryResult::UNAVAILABLE_AND_SUCCEED; + } else { + result = LoadLibraryResult::UNAVAILABLE_AND_FAIL; + } + return result; +} NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, - LoadLibraryFunction load_library_api, NativeLibraryLoadError* error) { // LoadLibrary() opens the file off disk. ThreadRestrictions::AssertIOAllowed(); + HMODULE module = nullptr; + + // This variable records the library loading result. + LoadLibraryResult load_library_result = LoadLibraryResult::SUCCEED; + + bool are_search_flags_available = AreSearchFlagsAvailable(); + if (are_search_flags_available) { + // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library + // directory as the library may have dependencies on DLLs in this + // directory. + module = ::LoadLibraryExW( + library_path.value().c_str(), nullptr, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + // If LoadLibraryExW succeeds, log this metric and return. + if (module) { + LogLibrarayLoadResultToUMA(load_library_result); + return module; + } + // GetLastError() needs to be called immediately after + // LoadLibraryExW call. + if (error) + error->code = GetLastError(); + } + + // If LoadLibraryExW API/flags are unavailable or API call fails, try + // LoadLibraryW API. + // TODO(chengx): Currently, if LoadLibraryExW API call fails, LoadLibraryW is + // still tried. We should strictly prefer the LoadLibraryExW over the + // LoadLibraryW if LoadLibraryW is statistically showing no extra benefits. If + // UMA metric shows that FAIL_AND_FAIL is the primary failure mode and/or + // FAIL_AND_SUCCESS is close to zero, we should remove this fallback. + // (http://crbug.com/701944) + // Switch the current directory to the library directory as the library // may have dependencies on DLLs in this directory. bool restore_directory = false; @@ -36,18 +129,21 @@ } } - HMODULE module = (*load_library_api)(library_path.value().c_str()); - if (!module && error) { - // GetLastError() needs to be called immediately after |load_library_api|. + module = ::LoadLibraryW(library_path.value().c_str()); + + // GetLastError() needs to be called immediately after LoadLibraryW call. + if (!module && error) error->code = GetLastError(); - } if (restore_directory) SetCurrentDirectory(current_directory); + // Get the library loading result and log it to UMA. + LogLibrarayLoadResultToUMA( + GetLoadLibraryResult(are_search_flags_available, !!module)); + return module; } - } // namespace std::string NativeLibraryLoadError::ToString() const { @@ -58,16 +154,7 @@ NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, const NativeLibraryOptions& options, NativeLibraryLoadError* error) { - return LoadNativeLibraryHelper(library_path, LoadLibraryW, error); -} - -NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) { - typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); - - LoadLibraryFunction load_library = reinterpret_cast<LoadLibraryFunction>( - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW")); - - return LoadNativeLibraryHelper(library_path, load_library, NULL); + return LoadNativeLibraryHelper(library_path, error); } // static
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index 71d6042e..aa26b902 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -188,6 +188,10 @@ // Returns the number of file descriptors currently open by the process, or // -1 on error. int GetOpenFdCount() const; + + // Returns the soft limit of file descriptors that can be opened by the + // process, or -1 on error. + int GetOpenFdSoftLimit() const; #endif // defined(OS_LINUX) private:
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc index 5d542cc..e507d16 100644 --- a/base/process/process_metrics_linux.cc +++ b/base/process/process_metrics_linux.cc
@@ -311,6 +311,32 @@ return total_count; } + +int ProcessMetrics::GetOpenFdSoftLimit() const { + // Use /proc/<pid>/limits to read the open fd limit. + FilePath fd_path = internal::GetProcPidDir(process_).Append("limits"); + + std::string limits_contents; + if (!ReadFileToString(fd_path, &limits_contents)) + return -1; + + for (const auto& line : + base::SplitStringPiece(limits_contents, "\n", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY)) { + if (line.starts_with("Max open files")) { + auto tokens = base::SplitStringPiece(line, " ", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + if (tokens.size() > 3) { + int limit = -1; + if (StringToInt(tokens[3], &limit)) + return limit; + return -1; + } + } + } + return -1; +} + #endif // defined(OS_LINUX) ProcessMetrics::ProcessMetrics(ProcessHandle process)
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java index aaa5c660..922536b 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
@@ -6,9 +6,10 @@ import android.content.Context; import android.support.test.InstrumentationRegistry; +import android.support.test.internal.runner.junit4.AndroidJUnit4ClassRunner; +import android.support.test.internal.util.AndroidRunnerParams; import org.junit.runner.notification.RunNotifier; -import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; @@ -25,8 +26,13 @@ /** * A custom runner for JUnit4 tests that checks requirements to conditionally ignore tests. + * + * This ClassRunner imports from AndroidJUnit4ClassRunner which is a hidden but accessible + * class. The reason is that default JUnit4 runner for Android is a final class, + * {@link AndroidJUnit4}. We need to extends an inheritable class to change {@link runChild} + * and {@link isIgnored} to add SkipChecks and PreTesthook. */ -public class BaseJUnit4ClassRunner extends BlockJUnit4ClassRunner { +public class BaseJUnit4ClassRunner extends AndroidJUnit4ClassRunner { private final List<SkipCheck> mSkipChecks; private final List<PreTestHook> mPreTestHooks; @@ -74,7 +80,9 @@ public BaseJUnit4ClassRunner( final Class<?> klass, List<SkipCheck> checks, List<PreTestHook> hooks) throws InitializationError { - super(klass); + super(klass, + new AndroidRunnerParams(InstrumentationRegistry.getInstrumentation(), + InstrumentationRegistry.getArguments(), false, 0L, false)); mSkipChecks = mergeList(checks, defaultSkipChecks()); mPreTestHooks = defaultPreTestHooks(); }
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn index 406f3f60..53366db 100644 --- a/build/android/BUILD.gn +++ b/build/android/BUILD.gn
@@ -125,16 +125,6 @@ ] } -group("logdog_wrapper_py") { - _py_files = read_file("test_wrapper/logdog_wrapper.pydeps", "list lines") - - # Filter out comments. - set_sources_assignment_filter([ "#*" ]) - sources = _py_files - - data = sources -} - # Create wrapper scripts in out/bin that takes care of setting the # --output-directory. _scripts_to_wrap = [
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 2c7fe8e..b3c1b97 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -12,7 +12,6 @@ import itertools import logging import os -import shutil import signal import sys import threading @@ -35,7 +34,6 @@ from pylib.base import test_run_factory from pylib.results import json_results from pylib.results import report_results -from pylib.utils import logdog_helper from py_utils import contextlib_ext @@ -218,12 +216,6 @@ help='Run the test under a tool ' '(use --tool help to list them)') - parser.add_argument( - '--upload-logcats-file', - action='store_true', - dest='upload_logcats_file', - help='Whether to upload logcat file to logdog.') - logcat_output_group = parser.add_mutually_exclusive_group() logcat_output_group.add_argument( '--logcat-output-dir', type=os.path.realpath, @@ -741,24 +733,6 @@ write_json_file(), args.json_results_file) - @contextlib.contextmanager - def upload_logcats_file(): - try: - yield - finally: - if not args.logcat_output_file: - logging.critical('Cannot upload logcats file. ' - 'File to save logcat is not specified.') - else: - with open(args.logcat_output_file) as src: - dst = logdog_helper.open_text('unified_logcats') - if dst: - shutil.copyfileobj(src, dst) - - logcats_uploader = contextlib_ext.Optional( - upload_logcats_file(), - 'upload_logcats_file' in args and args.upload_logcats_file) - ### Set up test objects. env = environment_factory.CreateEnvironment(args, infra_error) @@ -768,7 +742,7 @@ ### Run. - with json_writer, logcats_uploader, env, test_instance, test_run: + with json_writer, env, test_instance, test_run: repetitions = (xrange(args.repeat + 1) if args.repeat >= 0 else itertools.count())
diff --git a/build/android/test_wrapper/logdog_wrapper.py b/build/android/test_wrapper/logdog_wrapper.py index 0296650..14ed7d13 100755 --- a/build/android/test_wrapper/logdog_wrapper.py +++ b/build/android/test_wrapper/logdog_wrapper.py
@@ -11,76 +11,81 @@ import signal import subprocess import sys +import urllib -_SRC_PATH = os.path.abspath(os.path.join( - os.path.dirname(__file__), '..', '..', '..')) -sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')) -sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'common', - 'py_utils')) - -from devil.utils import signal_handler -from py_utils import tempfile_ext - -PROJECT = 'chromium' -OUTPUT = 'logdog' -COORDINATOR_HOST = 'luci-logdog.appspot.com' -SERVICE_ACCOUNT_JSON = ('/creds/service_accounts' - '/service-account-luci-logdog-publisher.json') def CommandParser(): # Parses the command line arguments being passed in parser = argparse.ArgumentParser() - parser.add_argument('--target', required=True, - help='The test target to be run.') parser.add_argument('--logdog-bin-cmd', required=True, - help='The logdog bin cmd.') + help='Command for running logdog butler binary') + parser.add_argument('--project', required=True, + help='Name of logdog project') + parser.add_argument('--logdog-server', + default='services-dot-luci-logdog.appspot.com', + help='URL of logdog server, https:// is assumed.') + parser.add_argument('--service-account-json', required=True, + help='Location of authentication json') + parser.add_argument('--prefix', required=True, + help='Prefix to be used for logdog stream') + parser.add_argument('--source', required=True, + help='Location of file for logdog to stream') + parser.add_argument('--name', required=True, + help='Name to be used for logdog stream') return parser -def CreateStopTestsMethod(proc): - def StopTests(signum, _frame): + +def CreateUrl(server, project, prefix, name): + stream_name = '%s/%s/+/%s' % (project, prefix, name) + return 'https://%s/v/?s=%s' % (server, urllib.quote_plus(stream_name)) + + +def CreateSignalForwarder(proc): + def handler(signum, _frame): logging.error('Forwarding signal %s to test process', str(signum)) proc.send_signal(signum) - return StopTests + + return handler + def main(): parser = CommandParser() - args, extra_cmd_args = parser.parse_known_args(sys.argv[1:]) - + args, test_cmd = parser.parse_known_args(sys.argv[1:]) logging.basicConfig(level=logging.INFO) - with tempfile_ext.NamedTemporaryDirectory() as logcat_output_dir: - test_cmd = [ - os.path.join('bin', 'run_%s' % args.target), - '--logcat-output-file', os.path.join(logcat_output_dir, 'logcats'), - '--upload-logcats-file', - '--target-devices-file', '${SWARMING_BOT_FILE}', - '-v'] + extra_cmd_args + if not test_cmd: + parser.error('Must specify command to run after the logdog flags') + test_proc = subprocess.Popen(test_cmd) + original_sigterm_handler = signal.signal( + signal.SIGTERM, CreateSignalForwarder(test_proc)) + try: + result = test_proc.wait() + finally: + signal.signal(signal.SIGTERM, original_sigterm_handler) + if '${SWARMING_TASK_ID}' in args.prefix: + args.prefix = args.prefix.replace('${SWARMING_TASK_ID}', + os.environ.get('SWARMING_TASK_ID')) + url = CreateUrl('luci-logdog.appspot.com', args.project, args.prefix, + args.name) + logdog_cmd = [args.logdog_bin_cmd, '-project', args.project, + '-output', 'logdog,host=%s' % args.logdog_server, + '-prefix', args.prefix, + '-service-account-json', args.service_account_json, + 'stream', '-source', args.source, + '-stream', '-name=%s' % args.name] - with tempfile_ext.NamedTemporaryDirectory( - prefix='tmp_android_logdog_wrapper') as temp_directory: - if not os.path.exists(args.logdog_bin_cmd): - logging.error( - 'Logdog binary %s unavailable. Unable to create logdog client', - args.logdog_bin_cmd) - else: - streamserver_uri = 'unix:%s' % os.path.join(temp_directory, - 'butler.sock') - prefix = os.path.join('android', 'swarming', 'logcats', - os.environ.get('SWARMING_TASK_ID')) + if not os.path.exists(args.logdog_bin_cmd): + logging.error( + 'Logdog binary %s unavailable. Unable to upload logcats.', + args.logdog_bin_cmd) + elif not os.path.exists(args.source): + logging.error( + 'Logcat sources not found at %s. Unable to upload logcats.', + args.source) + else: + subprocess.call(logdog_cmd) + logging.info('Logcats are located at: %s', url) + return result - # Call test_cmdline through logdog butler subcommand. - test_cmd = [ - args.logdog_bin_cmd, '-project', PROJECT, - '-output', OUTPUT, - '-prefix', prefix, - '--service-account-json', SERVICE_ACCOUNT_JSON, - '-coordinator-host', COORDINATOR_HOST, - 'run', '-streamserver-uri', streamserver_uri, '--'] + test_cmd - - test_proc = subprocess.Popen(test_cmd) - with signal_handler.SignalHandler(signal.SIGTERM, - CreateStopTestsMethod(test_proc)): - result = test_proc.wait() - return result if __name__ == '__main__': sys.exit(main())
diff --git a/build/android/test_wrapper/logdog_wrapper.pydeps b/build/android/test_wrapper/logdog_wrapper.pydeps deleted file mode 100644 index cd57f2fd..0000000 --- a/build/android/test_wrapper/logdog_wrapper.pydeps +++ /dev/null
@@ -1,11 +0,0 @@ -# Generated by running: -# build/print_python_deps.py --root build/android --output build/android/test_wrapper/logdog_wrapper.pydeps build/android/test_wrapper/logdog_wrapper.py -../../third_party/catapult/common/py_utils/py_utils/__init__.py -../../third_party/catapult/common/py_utils/py_utils/tempfile_ext.py -../../third_party/catapult/devil/devil/__init__.py -../../third_party/catapult/devil/devil/utils/__init__.py -../../third_party/catapult/devil/devil/utils/reraiser_thread.py -../../third_party/catapult/devil/devil/utils/signal_handler.py -../../third_party/catapult/devil/devil/utils/timeout_retry.py -../../third_party/catapult/devil/devil/utils/watchdog_timer.py -test_wrapper/logdog_wrapper.py
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 9ef8d27..d2d9f99 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -483,11 +483,7 @@ script = "//build/android/gyp/create_test_runner_script.py" depfile = "$target_gen_dir/$target_name.d" - data_deps += [ - "//build/android:test_runner_py", - "//build/android:logdog_wrapper_py", - ] - + data_deps += [ "//build/android:test_runner_py" ] data = [] test_runner_args = [
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn index 845d992..2a6c578 100644 --- a/build/config/sanitizers/BUILD.gn +++ b/build/config/sanitizers/BUILD.gn
@@ -385,6 +385,10 @@ ] } + if (use_cfi_icall) { + cflags += [ "-fsanitize=cfi-icall" ] + } + if (use_cfi_diag) { cflags += [ "-fno-sanitize-trap=cfi",
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 2a91c3d..6feef783 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -62,6 +62,11 @@ # https://crbug.com/626794 use_cfi_cast = false + # Enable checks for indirect function calls via a function pointer. + # TODO(pcc): remove this when we're ready to add these checks by default. + # https://crbug.com/701919 + use_cfi_icall = false + # By default, Control Flow Integrity will crash the program if it detects a # violation. Set this to true to print detailed diagnostics instead. use_cfi_diag = false
diff --git a/cc/input/scrollbar_animation_controller.cc b/cc/input/scrollbar_animation_controller.cc index 576ec2a..08bb917 100644 --- a/cc/input/scrollbar_animation_controller.cc +++ b/cc/input/scrollbar_animation_controller.cc
@@ -53,7 +53,6 @@ scroll_gesture_has_scrolled_(false), opacity_(0.0f), fade_out_duration_(fade_out_duration), - show_scrollbars_on_scroll_gesture_(false), need_thinning_animation_(false), weak_factory_(this) { ApplyOpacityToScrollbars(0.0f); @@ -78,7 +77,6 @@ scroll_gesture_has_scrolled_(false), opacity_(0.0f), fade_out_duration_(fade_out_duration), - show_scrollbars_on_scroll_gesture_(true), need_thinning_animation_(true), weak_factory_(this) { vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create( @@ -168,14 +166,39 @@ return std::max(std::min(progress, 1.f), 0.f); } +void ScrollbarAnimationController::DidScrollBegin() { + currently_scrolling_ = true; +} + void ScrollbarAnimationController::RunAnimationFrame(float progress) { ApplyOpacityToScrollbars(1.f - progress); if (progress == 1.f) StopAnimation(); } -void ScrollbarAnimationController::DidScrollBegin() { - currently_scrolling_ = true; +void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) { + if (need_thinning_animation_ && Captured()) + return; + + StopAnimation(); + + // As an optimization, we avoid spamming fade delay tasks during active fast + // scrolls. But if we're not within one, we need to post every scroll update. + if (!currently_scrolling_) { + // We don't fade out scrollbar if they need thinning animation and mouse is + // near. + if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar()) + PostDelayedFadeOut(on_resize); + } else { + scroll_gesture_has_scrolled_ = true; + } + + Show(); + + if (need_thinning_animation_) { + vertical_controller_->UpdateThumbThicknessScale(); + horizontal_controller_->UpdateThumbThicknessScale(); + } } void ScrollbarAnimationController::DidScrollEnd() { @@ -193,44 +216,6 @@ PostDelayedFadeOut(false); } -void ScrollbarAnimationController::DidScrollUpdate() { - if (need_thinning_animation_ && Captured()) - return; - - StopAnimation(); - - // As an optimization, we avoid spamming fade delay tasks during active fast - // scrolls. But if we're not within one, we need to post every scroll update. - if (!currently_scrolling_) { - // We don't fade out scrollbar if they need thinning animation and mouse is - // near. - if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar()) - PostDelayedFadeOut(false); - } else { - scroll_gesture_has_scrolled_ = true; - } - - Show(); - - if (need_thinning_animation_) { - vertical_controller_->UpdateThumbThicknessScale(); - horizontal_controller_->UpdateThumbThicknessScale(); - } -} - -void ScrollbarAnimationController::WillUpdateScroll() { - if (show_scrollbars_on_scroll_gesture_) - DidScrollUpdate(); -} - -void ScrollbarAnimationController::DidResize() { - StopAnimation(); - Show(); - // We should use the gesture delay rather than the resize delay if we're in a - // gesture scroll, even if it is resizing. - PostDelayedFadeOut(!currently_scrolling_); -} - void ScrollbarAnimationController::DidMouseDown() { if (!need_thinning_animation_ || ScrollbarsHidden()) return;
diff --git a/cc/input/scrollbar_animation_controller.h b/cc/input/scrollbar_animation_controller.h index 2623543..02f8e97 100644 --- a/cc/input/scrollbar_animation_controller.h +++ b/cc/input/scrollbar_animation_controller.h
@@ -65,19 +65,8 @@ bool Animate(base::TimeTicks now); - // WillUpdateScroll expects to be called even if the scroll position won't - // change as a result of the scroll. Only effect Aura Overlay Scrollbar. - void WillUpdateScroll(); - - // DidScrollUpdate expects to be called only if the scroll position change. - // Effect both Android and Aura Overlay Scrollbar. - void DidScrollUpdate(); - - // DidResize expects to be called when clip layer size changed or scroll layer - // size changed. - void DidResize(); - void DidScrollBegin(); + void DidScrollUpdate(bool on_resize); void DidScrollEnd(); void DidMouseDown(); @@ -154,7 +143,6 @@ float opacity_; base::TimeDelta fade_out_duration_; - const bool show_scrollbars_on_scroll_gesture_; const bool need_thinning_animation_; std::unique_ptr<SingleScrollbarAnimationControllerThinning> vertical_controller_;
diff --git a/cc/input/scrollbar_animation_controller_unittest.cc b/cc/input/scrollbar_animation_controller_unittest.cc index c4470c14..3d0855e 100644 --- a/cc/input/scrollbar_animation_controller_unittest.cc +++ b/cc/input/scrollbar_animation_controller_unittest.cc
@@ -145,18 +145,18 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); ExpectScrollbarsOpacity(1); // Make the Layer non-scrollable, scrollbar disappears. clip_layer_->SetBounds(gfx::Size(200, 200)); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); ExpectScrollbarsOpacity(0); // Make the layer scrollable, scrollbar appears again. clip_layer_->SetBounds(gfx::Size(100, 100)); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); ExpectScrollbarsOpacity(1); } @@ -175,7 +175,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -187,7 +187,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(0.0f, h_scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -207,7 +207,7 @@ ExpectScrollbarsOpacity(0); EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); ExpectScrollbarsOpacity(1); EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); @@ -229,35 +229,6 @@ EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); } -// Confirm the scrollbar appears by WillUpdateScroll and fade out. -TEST_F(ScrollbarAnimationControllerAuraOverlayTest, - BasicAppearByWillUpdateScrollThenFadeOut) { - base::TimeTicks time; - time += base::TimeDelta::FromSeconds(1); - - // Scrollbar should be invisible. - ExpectScrollbarsOpacity(0); - EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); - - // Scrollbar should appear when scroll will update. - scrollbar_controller_->WillUpdateScroll(); - ExpectScrollbarsOpacity(1); - EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); - - // An fade out animation should have been enqueued. - EXPECT_EQ(kFadeOutDelay, client_.delay()); - EXPECT_FALSE(client_.start_fade().is_null()); - client_.start_fade().Run(); - - // Scrollbar should fade out over kFadeOutDuration. - scrollbar_controller_->Animate(time); - time += kFadeOutDuration; - scrollbar_controller_->Animate(time); - - ExpectScrollbarsOpacity(0); - EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); -} - // Scroll content. Move the mouse near the scrollbar and confirm it becomes // thick. Ensure it remains visible as long as the mouse is near the scrollbar. TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveNearAndDontFadeOut) { @@ -265,7 +236,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -306,7 +277,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -348,7 +319,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -376,7 +347,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -412,7 +383,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -449,7 +420,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -500,7 +471,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // An fade out animation should have been enqueued. @@ -539,7 +510,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // A fade out animation should have been enqueued. Start it. @@ -579,7 +550,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); EXPECT_EQ(kFadeOutDelay, client_.delay()); @@ -643,7 +614,7 @@ h_scrollbar_layer_->thumb_thickness_scale_factor()); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); // Now that we've received a scroll, we should be thick without an animation. ExpectScrollbarsOpacity(1); @@ -678,7 +649,7 @@ // A ScrollUpdate without a ScrollBegin indicates a main thread scroll update // so we should schedule a fade out animation without waiting for a ScrollEnd // (which will never come). - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(client_.start_fade().is_null()); EXPECT_EQ(kFadeOutDelay, client_.delay()); @@ -687,7 +658,7 @@ // If we got a ScrollBegin, we shouldn't schedule the fade out animation until // we get a corresponding ScrollEnd. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_TRUE(client_.start_fade().is_null()); scrollbar_controller_->DidScrollEnd(); EXPECT_FALSE(client_.start_fade().is_null()); @@ -699,16 +670,16 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ResizeFadeDuration) { ASSERT_TRUE(client_.delay().is_zero()); - scrollbar_controller_->DidResize(); + scrollbar_controller_->DidScrollUpdate(true); EXPECT_FALSE(client_.start_fade().is_null()); EXPECT_EQ(kResizeFadeOutDelay, client_.delay()); client_.delay() = base::TimeDelta(); // We should use the gesture delay rather than the resize delay if we're in a - // gesture scroll, even if it is resizing. + // gesture scroll, even if the resize param is set. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidResize(); + scrollbar_controller_->DidScrollUpdate(true); scrollbar_controller_->DidScrollEnd(); EXPECT_FALSE(client_.start_fade().is_null()); @@ -722,7 +693,7 @@ // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // Appearance is instant. @@ -754,7 +725,7 @@ EXPECT_CALL(client_, DidChangeScrollbarVisibility()).Times(1); // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); Mock::VerifyAndClearExpectations(&client_); @@ -789,7 +760,7 @@ // Calling DidScrollUpdate without a begin (i.e. update from commit) should // also notify. EXPECT_CALL(client_, DidChangeScrollbarVisibility()).Times(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden()); Mock::VerifyAndClearExpectations(&client_); } @@ -802,7 +773,7 @@ // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // Near vertical scrollbar @@ -895,7 +866,7 @@ // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // Near both Scrollbar @@ -925,7 +896,7 @@ // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // Near vertical scrollbar. @@ -991,7 +962,7 @@ // Scroll to make the scrollbars visible. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); // Should not have delay fadeout animation. @@ -1177,10 +1148,8 @@ ->effect_tree.OnOpacityAnimated(0.0f, scrollbar_layer_->effect_tree_index(), scrollbar_layer_->layer_tree_impl()); - // We should use the gesture delay rather than the resize delay if we're in a - // gesture scroll, even if it is resizing. scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidResize(); + scrollbar_controller_->DidScrollUpdate(true); scrollbar_controller_->DidScrollEnd(); // Normal Animation delay of 2 seconds. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); @@ -1191,7 +1160,7 @@ ->effect_tree.OnOpacityAnimated(0.0f, scrollbar_layer_->effect_tree_index(), scrollbar_layer_->layer_tree_impl()); - scrollbar_controller_->DidResize(); + scrollbar_controller_->DidScrollUpdate(true); // Delay animation on resize to 5 seconds. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); EXPECT_EQ(delay_, base::TimeDelta::FromSeconds(5)); @@ -1229,25 +1198,6 @@ EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); } -// Confirm the scrollbar does not appear on WillUpdateScroll on Android. -TEST_F(ScrollbarAnimationControllerAndroidTest, - WillUpdateScrollNotAppearScrollbar) { - base::TimeTicks time; - time += base::TimeDelta::FromSeconds(1); - - // Scrollbar should be invisible. - EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); - EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); - - // Scrollbar should appear when scroll will update. - scrollbar_controller_->WillUpdateScroll(); - EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); - EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden()); - - // No fade out animation should have been enqueued. - EXPECT_TRUE(start_fade_.Equals(base::Closure())); -} - TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) { LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1); ASSERT_TRUE(scroll_layer); @@ -1261,7 +1211,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1273,7 +1223,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1292,7 +1242,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1303,7 +1253,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1318,7 +1268,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1333,7 +1283,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1349,7 +1299,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1365,7 +1315,7 @@ scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); scrollbar_controller_->DidScrollEnd(); @@ -1377,7 +1327,7 @@ scrollbar_controller_->DidScrollBegin(); EXPECT_FALSE(did_request_animate_); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(did_request_animate_); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity()); @@ -1415,7 +1365,7 @@ time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidScrollBegin(); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); scrollbar_controller_->DidScrollEnd(); start_fade_.Run(); @@ -1449,7 +1399,7 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, AwakenByProgrammaticScroll) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(did_request_animate_); start_fade_.Run(); @@ -1465,7 +1415,7 @@ EXPECT_TRUE(did_request_animate_); did_request_animate_ = false; EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->Opacity()); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(did_request_animate_); start_fade_.Run(); @@ -1490,7 +1440,7 @@ EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->Opacity()); time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); start_fade_.Run(); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); @@ -1520,7 +1470,7 @@ AnimationPreservedByNonScrollingGesture) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); start_fade_.Run(); EXPECT_TRUE(did_request_animate_); did_request_animate_ = false; @@ -1559,7 +1509,7 @@ AnimationOverriddenByScrollingGesture) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(did_request_animate_); start_fade_.Run(); EXPECT_TRUE(did_request_animate_); @@ -1585,7 +1535,7 @@ EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->Opacity()); time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollUpdate(); + scrollbar_controller_->DidScrollUpdate(false); EXPECT_FALSE(did_request_animate_); EXPECT_FLOAT_EQ(1, scrollbar_layer_->Opacity());
diff --git a/cc/output/color_lut_cache.cc b/cc/output/color_lut_cache.cc index 4cc7220..1a796db 100644 --- a/cc/output/color_lut_cache.cc +++ b/cc/output/color_lut_cache.cc
@@ -103,11 +103,11 @@ } LUT lut; - // If input is HDR, and the output is scRGB, we're going to need + // If input is HDR, and the output is full range, we're going to need // to produce values outside of 0-1, so we'll need to make a half-float // LUT. Also, we'll need to build a larger lut to maintain accuracy. - // All LUT sizes should be odd a some transforms hav a knee at 0.5. - if (transform->GetDstColorSpace() == gfx::ColorSpace::CreateSCRGBLinear() && + // All LUT sizes should be odd as some transforms have a knee at 0.5. + if (transform->GetDstColorSpace().FullRangeEncodedValues() && transform->GetSrcColorSpace().IsHDR() && texture_half_float_linear_) { lut.size = 37; lut.texture = MakeLUT<uint16_t>(transform, lut.size);
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index dfd32560..7c53b513 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc
@@ -150,7 +150,7 @@ current_canvas_->resetMatrix(); // TODO(fmalita) stop using kReplace (see crbug.com/673851) current_canvas_->clipRect(gfx::RectToSkRect(rect), - SkClipOp::kReplace_private_internal_do_not_use); + SkClipOp::kReplace_deprecated); current_canvas_->setMatrix(current_matrix); }
diff --git a/cc/playback/discardable_image_map.cc b/cc/playback/discardable_image_map.cc index cf424fe..c6129d1d 100644 --- a/cc/playback/discardable_image_map.cc +++ b/cc/playback/discardable_image_map.cc
@@ -172,6 +172,7 @@ return false; *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds); } + return true; } @@ -202,6 +203,18 @@ src_rect.roundOut(&src_irect); gfx::Rect image_rect = SafeClampPaintRectToSize(paint_rect, canvas_size_); + // During raster, we use the device clip bounds on the canvas, which outsets + // the actual clip by 1 due to the possibility of antialiasing. Account for + // this here by outsetting the image rect by 1. Note that this only affects + // queries into the rtree, which will now return images that only touch the + // bounds of the query rect. + // + // Note that it's not sufficient for us to inset the device clip bounds at + // raster time, since we might be sending a larger-than-one-item display + // item to skia, which means that skia will internally determine whether to + // raster the picture (using device clip bounds that are outset). + image_rect.Inset(-1, -1); + (*image_id_to_rect_)[image->uniqueID()].Union(image_rect); image_set_->push_back(std::make_pair( DrawImage(std::move(image), src_irect, filter_quality, matrix),
diff --git a/cc/playback/discardable_image_map_unittest.cc b/cc/playback/discardable_image_map_unittest.cc index ff8441e..eee782e 100644 --- a/cc/playback/discardable_image_map_unittest.cc +++ b/cc/playback/discardable_image_map_unittest.cc
@@ -60,6 +60,18 @@ EXPECT_TRUE(draw_images[i].image() == position_draw_images[i].image); return position_draw_images; } + + // Note that the image rtree outsets the images by 1, see the comment in + // DiscardableImagesMetadataCanvas::AddImage. + std::vector<gfx::Rect> InsetImageRects( + const std::vector<PositionScaleDrawImage>& images) { + std::vector<gfx::Rect> result; + for (auto& image : images) { + result.push_back(image.image_rect); + result.back().Inset(1, 1, 1, 1); + } + return result; + } }; TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) { @@ -105,12 +117,13 @@ for (int x = 0; x < 4; ++x) { std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect( image_map, gfx::Rect(x * 512, y * 512, 500, 500)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); if ((x + y) & 1) { EXPECT_EQ(1u, images.size()) << x << " " << y; EXPECT_TRUE(images[0].image == discardable_image[y][x]) << x << " " << y; EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500), - images[0].image_rect); + inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); } else { @@ -122,27 +135,26 @@ // Capture 4 pixel refs. std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(512, 512, 2048, 2048)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(4u, images.size()); EXPECT_TRUE(images[0].image == discardable_image[1][2]); - EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), images[0].image_rect); + EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); EXPECT_TRUE(images[1].image == discardable_image[2][1]); - EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), images[1].image_rect); + EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]); EXPECT_EQ(images[1].image_rect, image_map.GetRectForImage(images[1].image->uniqueID())); EXPECT_TRUE(images[2].image == discardable_image[2][3]); - EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), - images[2].image_rect); + EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[2]); EXPECT_EQ(images[2].image_rect, image_map.GetRectForImage(images[2].image->uniqueID())); EXPECT_TRUE(images[3].image == discardable_image[3][2]); - EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), - images[3].image_rect); + EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), inset_rects[3]); EXPECT_EQ(images[3].image_rect, image_map.GetRectForImage(images[3].image->uniqueID())); } @@ -192,12 +204,13 @@ for (int x = 0; x < 4; ++x) { std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect( image_map, gfx::Rect(1024 + x * 512, y * 512, 500, 500)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); if ((x + y) & 1) { EXPECT_EQ(1u, images.size()) << x << " " << y; EXPECT_TRUE(images[0].image == discardable_image[y][x]) << x << " " << y; EXPECT_EQ(gfx::Rect(1024 + x * 512 + 6, y * 512 + 6, 500, 500), - images[0].image_rect); + inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); } else { @@ -209,29 +222,28 @@ { std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect( image_map, gfx::Rect(1024 + 512, 512, 2048, 2048)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(4u, images.size()); EXPECT_TRUE(images[0].image == discardable_image[1][2]); - EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 512 + 6, 500, 500), - images[0].image_rect); + EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); EXPECT_TRUE(images[1].image == discardable_image[2][1]); - EXPECT_EQ(gfx::Rect(1024 + 512 + 6, 2 * 512 + 6, 500, 500), - images[1].image_rect); + EXPECT_EQ(gfx::Rect(1024 + 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]); EXPECT_EQ(images[1].image_rect, image_map.GetRectForImage(images[1].image->uniqueID())); EXPECT_TRUE(images[2].image == discardable_image[2][3]); EXPECT_EQ(gfx::Rect(1024 + 3 * 512 + 6, 2 * 512 + 6, 500, 500), - images[2].image_rect); + inset_rects[2]); EXPECT_EQ(images[2].image_rect, image_map.GetRectForImage(images[2].image->uniqueID())); EXPECT_TRUE(images[3].image == discardable_image[3][2]); EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 3 * 512 + 6, 500, 500), - images[3].image_rect); + inset_rects[3]); EXPECT_EQ(images[3].image_rect, image_map.GetRectForImage(images[3].image->uniqueID())); } @@ -308,12 +320,13 @@ for (int x = 0; x < 4; ++x) { std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect( image_map, gfx::Rect(x * 512 + 256, y * 512 + 256, 1, 1)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); if ((x + y) & 1) { EXPECT_EQ(1u, images.size()) << x << " " << y; EXPECT_TRUE(images[0].image == discardable_image[y][x]) << x << " " << y; EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500), - images[0].image_rect); + inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); } else { @@ -346,9 +359,10 @@ } std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); EXPECT_TRUE(images[0].image == discardable_image); - EXPECT_EQ(gfx::Rect(0, 0, 2048, 2048), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, 2048, 2048), inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); } @@ -426,9 +440,10 @@ } std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(42, 42, 1, 1)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); EXPECT_TRUE(images[0].image == discardable_image); - EXPECT_EQ(gfx::Rect(42, 42, 2006, 2006), images[0].image_rect); + EXPECT_EQ(gfx::Rect(42, 42, 2006, 2006), inset_rects[0]); EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(images[0].image->uniqueID())); } @@ -467,14 +482,15 @@ } std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); - EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), inset_rects[0]); images = GetDiscardableImagesInRect(image_map, gfx::Rect(10000, 0, 1, 1)); + inset_rects = InsetImageRects(images); EXPECT_EQ(2u, images.size()); - EXPECT_EQ(gfx::Rect(10000, 0, dimension - 10000, dimension), - images[1].image_rect); - EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); + EXPECT_EQ(gfx::Rect(10000, 0, dimension - 10000, dimension), inset_rects[1]); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), inset_rects[0]); // Since we adjust negative offsets before using ToEnclosingRect, the expected // width will be converted to float, which means that we lose some precision. @@ -482,12 +498,12 @@ // back to int. int expected10k = static_cast<int>(static_cast<float>(dimension - 10000)); images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 500, 1, 1)); + inset_rects = InsetImageRects(images); EXPECT_EQ(2u, images.size()); - EXPECT_EQ(gfx::Rect(0, 500, expected10k, dimension - 500), - images[1].image_rect); - EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 500, expected10k, dimension - 500), inset_rects[1]); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), inset_rects[0]); - EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), + EXPECT_EQ(images[0].image_rect, image_map.GetRectForImage(discardable_image->uniqueID())); } @@ -521,24 +537,28 @@ } std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); - EXPECT_EQ(gfx::Rect(0, 0, 90, 89), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, 90, 89), inset_rects[0]); images = GetDiscardableImagesInRect(image_map, gfx::Rect(999, 999, 1, 1)); + inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); - EXPECT_EQ(gfx::Rect(950, 951, 50, 49), images[0].image_rect); + EXPECT_EQ(gfx::Rect(950, 951, 50, 49), inset_rects[0]); images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 500, 1, 1)); + inset_rects = InsetImageRects(images); EXPECT_EQ(1u, images.size()); - EXPECT_EQ(gfx::Rect(0, 500, 1000, 100), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 500, 1000, 100), inset_rects[0]); gfx::Rect discardable_image_rect; discardable_image_rect.Union(gfx::Rect(0, 0, 90, 89)); discardable_image_rect.Union(gfx::Rect(950, 951, 50, 49)); + discardable_image_rect.Inset(-1, -1, -1, -1); EXPECT_EQ(discardable_image_rect, image_map.GetRectForImage(discardable_image->uniqueID())); - EXPECT_EQ(gfx::Rect(0, 500, 1000, 100), + EXPECT_EQ(gfx::Rect(-1, 499, 1002, 102), image_map.GetRectForImage(long_discardable_image->uniqueID())); } @@ -593,12 +613,13 @@ for (int x = 0; x < 4; ++x) { std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect( image_map, gfx::Rect(x * 512, y * 512, 500, 500)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); if ((x + y) & 1) { EXPECT_EQ(1u, images.size()) << x << " " << y; EXPECT_TRUE(images[0].image == discardable_image[y][x]) << x << " " << y; EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500), - images[0].image_rect); + inset_rects[0]); EXPECT_EQ(std::max(x * 0.5f, kMinScale), images[0].scale.fWidth); EXPECT_EQ(std::max(y * 0.5f, kMinScale), images[0].scale.fHeight); } else { @@ -610,17 +631,16 @@ // Capture 4 pixel refs. std::vector<PositionScaleDrawImage> images = GetDiscardableImagesInRect(image_map, gfx::Rect(512, 512, 2048, 2048)); + std::vector<gfx::Rect> inset_rects = InsetImageRects(images); EXPECT_EQ(4u, images.size()); EXPECT_TRUE(images[0].image == discardable_image[1][2]); - EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), images[0].image_rect); + EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]); EXPECT_TRUE(images[1].image == discardable_image[2][1]); - EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), images[1].image_rect); + EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]); EXPECT_TRUE(images[2].image == discardable_image[2][3]); - EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), - images[2].image_rect); + EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[2]); EXPECT_TRUE(images[3].image == discardable_image[3][2]); - EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), - images[3].image_rect); + EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), inset_rects[3]); } } // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 0051d95..c7238e8 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2904,15 +2904,7 @@ MainThreadScrollingReason::kNotScrollingOnMain; ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode(); - if (scroll_node) { - // Flash the overlay scrollbar even if the scroll dalta is 0. - ScrollbarAnimationController* animation_controller = - ScrollbarAnimationControllerForId(scroll_node->owning_layer_id); - - if (animation_controller) - animation_controller->WillUpdateScroll(); - gfx::Vector2dF delta = scroll_delta; if (!scroll_node->user_scrollable_horizontal) delta.set_x(0); @@ -2951,13 +2943,6 @@ viewport()->MainScrollLayer() && viewport()->MainScrollLayer()->scroll_tree_index() == scroll_node->id; if (scrolls_main_viewport_scroll_layer) { - // Flash the overlay scrollbar even if the scroll dalta is 0. - ScrollbarAnimationController* animation_controller = - ScrollbarAnimationControllerForId(scroll_node->owning_layer_id); - - if (animation_controller) - animation_controller->WillUpdateScroll(); - gfx::Vector2dF scrolled = viewport()->ScrollAnimated(pending_delta, delayed_by); // Viewport::ScrollAnimated returns pending_delta as long as it starts @@ -3202,18 +3187,9 @@ DCHECK(scroll_state); TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy"); - ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; - ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode(); - - if (!scroll_node) + if (!CurrentlyScrollingNode()) return InputHandlerScrollResult(); - ScrollbarAnimationController* animation_controller = - ScrollbarAnimationControllerForId(scroll_node->owning_layer_id); - - if (animation_controller) - animation_controller->WillUpdateScroll(); - float initial_top_controls_offset = browser_controls_offset_manager_->ControlsTopOffset();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index f6e8f731..c74072b 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -2814,8 +2814,6 @@ settings.scrollbar_animator = animator; settings.scrollbar_show_delay = base::TimeDelta::FromMilliseconds(20); settings.scrollbar_fade_out_delay = base::TimeDelta::FromMilliseconds(20); - settings.scrollbar_fade_out_resize_delay = - base::TimeDelta::FromMilliseconds(20); settings.scrollbar_fade_out_duration = base::TimeDelta::FromMilliseconds(20); @@ -2849,25 +2847,6 @@ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); - // For Aura Overlay Scrollbar, if no scroll happened during a scroll - // gesture, shows scrollbars and schedules a delay fade out. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL); - host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 0)).get()); - host_impl_->ScrollEnd(EndState().get()); - EXPECT_FALSE(did_request_next_frame_); - EXPECT_FALSE(did_request_redraw_); - if (animator == LayerTreeSettings::AURA_OVERLAY) { - EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), - requested_animation_delay_); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - requested_animation_delay_ = base::TimeDelta(); - animation_task_ = base::Closure(); - } else { - EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); - EXPECT_TRUE(animation_task_.Equals(base::Closure())); - } - // Before the scrollbar animation exists, we should not get redraws. BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2, fake_now); @@ -2975,9 +2954,7 @@ host_impl_->DidFinishImplFrame(); } - // For Andrdoid, scrollbar animation is not triggered unnecessarily. - // For Aura Overlay Scrollbar, scrollbar appears even if scroll offset did - // not change. + // Scrollbar animation is not triggered unnecessarily. host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(5, 0)).get()); @@ -2990,16 +2967,8 @@ host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); - if (animator == LayerTreeSettings::AURA_OVERLAY) { - EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), - requested_animation_delay_); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - requested_animation_delay_ = base::TimeDelta(); - animation_task_ = base::Closure(); - } else { - EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); - EXPECT_TRUE(animation_task_.Equals(base::Closure())); - } + EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); + EXPECT_TRUE(animation_task_.Equals(base::Closure())); // Changing page scale triggers scrollbar animation. host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f);
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index b069051..a42bd683 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -243,31 +243,27 @@ } bool scrollbar_needs_animation = false; - bool clip_layer_size_did_change = false; bool scroll_layer_size_did_change = false; bool y_offset_did_change = false; for (ScrollbarLayerImplBase* scrollbar : ScrollbarsFor(scroll_layer_id)) { if (scrollbar->orientation() == HORIZONTAL) { scrollbar_needs_animation |= scrollbar->SetCurrentPos(current_offset.x()); - clip_layer_size_did_change |= + scrollbar_needs_animation |= scrollbar->SetClipLayerLength(clip_size.width()); - scroll_layer_size_did_change |= + scrollbar_needs_animation |= scroll_layer_size_did_change |= scrollbar->SetScrollLayerLength(scroll_size.width()); } else { scrollbar_needs_animation |= y_offset_did_change |= scrollbar->SetCurrentPos(current_offset.y()); - clip_layer_size_did_change |= + scrollbar_needs_animation |= scrollbar->SetClipLayerLength(clip_size.height()); - scroll_layer_size_did_change |= + scrollbar_needs_animation |= scroll_layer_size_did_change |= scrollbar->SetScrollLayerLength(scroll_size.height()); } scrollbar_needs_animation |= scrollbar->SetVerticalAdjust(clip_layer->bounds_delta().y()); } - scrollbar_needs_animation |= - (clip_layer_size_did_change || scroll_layer_size_did_change); - if (y_offset_did_change && IsViewportLayerId(scroll_layer_id)) TRACE_COUNTER_ID1("cc", "scroll_offset_y", scroll_layer->id(), current_offset.y()); @@ -276,14 +272,8 @@ ScrollbarAnimationController* controller = layer_tree_host_impl_->ScrollbarAnimationControllerForId( scroll_layer_id); - if (!controller) - return; - - if (clip_layer_size_did_change || scroll_layer_size_did_change) { - controller->DidResize(); - } else { - controller->DidScrollUpdate(); - } + if (controller) + controller->DidScrollUpdate(scroll_layer_size_did_change); } } @@ -1281,6 +1271,10 @@ // These manage ownership of the LayerImpl. void LayerTreeImpl::AddLayer(std::unique_ptr<LayerImpl> layer) { DCHECK(std::find(layers_->begin(), layers_->end(), layer) == layers_->end()); + + // TODO(ajuma): Change this to a DCHECK once we've figured out what's causing + // crbug.com/701279. + CHECK(layer); layers_->push_back(std::move(layer)); set_needs_update_draw_properties(); }
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc index b593a9d6..873a57bf 100644 --- a/cc/trees/tree_synchronizer.cc +++ b/cc/trees/tree_synchronizer.cc
@@ -28,8 +28,12 @@ std::unique_ptr<OwnedLayerImplList> old_layers(tree_impl->DetachLayers()); OwnedLayerImplMap old_layer_map; - for (auto& it : *old_layers) + for (auto& it : *old_layers) { + // TODO(ajuma): Remove this once we've figured out what's causing + // crbug.com/701279. + CHECK(it); old_layer_map[it->id()] = std::move(it); + } PushLayerList(&old_layer_map, source_tree, tree_impl);
diff --git a/chrome/VERSION b/chrome/VERSION index 9db4e92..402b4a6 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=59 MINOR=0 -BUILD=3043 +BUILD=3044 PATCH=0
diff --git a/chrome/android/java/res/drawable-hdpi/chrome_sync_logo.png b/chrome/android/java/res/drawable-hdpi/chrome_sync_logo.png index ed53451..22af647 100644 --- a/chrome/android/java/res/drawable-hdpi/chrome_sync_logo.png +++ b/chrome/android/java/res/drawable-hdpi/chrome_sync_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_history_grey600_24dp.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_history_grey600_24dp.png deleted file mode 100644 index 6571bf73..0000000 --- a/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_history_grey600_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_history_grey600_24dp.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_history_grey600_24dp.png deleted file mode 100644 index 41f31a0..0000000 --- a/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_history_grey600_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_history_grey600_24dp.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_history_grey600_24dp.png deleted file mode 100644 index f04d215..0000000 --- a/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_history_grey600_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_history_grey600_24dp.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_history_grey600_24dp.png deleted file mode 100644 index 03c7448..0000000 --- a/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_history_grey600_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_history_grey600_24dp.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_history_grey600_24dp.png deleted file mode 100644 index 37803b6a..0000000 --- a/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_history_grey600_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/chrome_sync_logo.png b/chrome/android/java/res/drawable-mdpi/chrome_sync_logo.png index 122de7b..0504718 100644 --- a/chrome/android/java/res/drawable-mdpi/chrome_sync_logo.png +++ b/chrome/android/java/res/drawable-mdpi/chrome_sync_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/chrome_sync_logo.png b/chrome/android/java/res/drawable-xhdpi/chrome_sync_logo.png index d4af888..ce3a32b 100644 --- a/chrome/android/java/res/drawable-xhdpi/chrome_sync_logo.png +++ b/chrome/android/java/res/drawable-xhdpi/chrome_sync_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/chrome_sync_logo.png b/chrome/android/java/res/drawable-xxxhdpi/chrome_sync_logo.png index 01760ec..bcc72c1 100644 --- a/chrome/android/java/res/drawable-xxxhdpi/chrome_sync_logo.png +++ b/chrome/android/java/res/drawable-xxxhdpi/chrome_sync_logo.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/search_sogou.png b/chrome/android/java/res/drawable-xxxhdpi/search_sogou.png index 170a5df5..96413939 100644 --- a/chrome/android/java/res/drawable-xxxhdpi/search_sogou.png +++ b/chrome/android/java/res/drawable-xxxhdpi/search_sogou.png Binary files differ
diff --git a/chrome/android/java/res/layout/bottom_control_container.xml b/chrome/android/java/res/layout/bottom_control_container.xml index 9f45f2a4..2ff0eab 100644 --- a/chrome/android/java/res/layout/bottom_control_container.xml +++ b/chrome/android/java/res/layout/bottom_control_container.xml
@@ -13,12 +13,13 @@ android:id="@+id/control_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/control_container_height" > + android:minHeight="@dimen/bottom_control_container_height" > + <view class="org.chromium.chrome.browser.toolbar.ToolbarControlContainer$ToolbarViewResourceFrameLayout" android:id="@+id/toolbar_container" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" > <ImageView android:id="@+id/bottom_toolbar_shadow" android:layout_width="match_parent" @@ -30,16 +31,22 @@ <ViewStub android:id="@+id/toolbar_stub" android:layout_width="match_parent" - android:layout_height="@dimen/toolbar_height_no_shadow" + android:layout_height="@dimen/bottom_control_container_height" android:layout_marginTop="@dimen/toolbar_shadow_height" /> <ViewStub android:id="@+id/find_toolbar_stub" android:inflatedId="@+id/find_toolbar" android:layout_marginTop="@dimen/toolbar_shadow_height" android:layout_width="match_parent" - android:layout_height="@dimen/toolbar_height_no_shadow" - android:layout="@layout/find_toolbar" - android:visibility="gone" /> + android:layout_height="@dimen/bottom_control_container_height" + android:layout="@layout/find_toolbar" /> + <ImageView + android:id="@+id/toolbar_handle" + android:layout_width="@dimen/toolbar_handle_width" + android:layout_height="@dimen/toolbar_handle_height" + android:layout_marginTop="@dimen/toolbar_handle_margin_top" + android:layout_gravity="center|top" + android:contentDescription="@null" /> </view> </org.chromium.chrome.browser.toolbar.ToolbarControlContainer>
diff --git a/chrome/android/java/res/layout/bottom_toolbar_phone.xml b/chrome/android/java/res/layout/bottom_toolbar_phone.xml index 00d1b0b..9dc4891 100644 --- a/chrome/android/java/res/layout/bottom_toolbar_phone.xml +++ b/chrome/android/java/res/layout/bottom_toolbar_phone.xml
@@ -10,7 +10,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_width="match_parent" - android:layout_height="@dimen/toolbar_height_no_shadow" > + android:layout_height="match_parent" > <include layout="@layout/toolbar_phone_common"/>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml index 0e3ebd21..d156c87 100644 --- a/chrome/android/java/res/values/colors.xml +++ b/chrome/android/java/res/values/colors.xml
@@ -27,6 +27,7 @@ <color name="google_grey_600">#757575</color> <color name="google_grey_700">#616161</color> <color name="toolbar_shadow_color">#1d000000</color> + <color name="semi_opaque_white">#80ffffff</color> <color name="toolbar_light_tint">#A3000000</color> <color name="light_grey">#ccc</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index bd848cf..fb3f6e0 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -190,6 +190,8 @@ <!-- Full Screen Dimensions --> <!-- Should match toolbar_height_no_shadow --> <dimen name="control_container_height">56dp</dimen> + <dimen name="bottom_control_container_height">64dp</dimen> + <dimen name="bottom_toolbar_top_margin">8dp</dimen> <dimen name="custom_tabs_control_container_height">56dp</dimen> <dimen name="webapp_control_container_height">22dp</dimen> @@ -232,6 +234,9 @@ <dimen name="toolbar_shadow_height">8dp</dimen> <dimen name="toolbar_progress_bar_height">2dp</dimen> <dimen name="toolbar_button_width">48dp</dimen> + <dimen name="toolbar_handle_height">4dp</dimen> + <dimen name="toolbar_handle_width">40dp</dimen> + <dimen name="toolbar_handle_margin_top">14dp</dimen> <dimen name="toolbar_edge_padding">8dp</dimen> <dimen name="location_bar_google_g_width">24dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index cabf212d..d5e46096 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1351,6 +1351,7 @@ * @return The resource id that contains how large the browser controls are. */ public int getControlContainerHeightResource() { + if (mBottomSheet != null) return R.dimen.bottom_control_container_height; return R.dimen.control_container_height; } @@ -1668,6 +1669,7 @@ * and visa-versa. * @param isInMultiWindowMode True if the activity is in multi-window mode. */ + @Override public void onMultiWindowModeChanged(boolean isInMultiWindowMode) { recordMultiWindowModeChangedUserAction(isInMultiWindowMode);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java index 5933a66a8..be825b1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java
@@ -4,12 +4,17 @@ package org.chromium.chrome.browser.compositor.layouts; +import android.annotation.TargetApi; +import android.os.Build; import android.os.SystemClock; +import android.provider.Settings; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; +import org.chromium.base.ContextUtils; + import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -31,9 +36,10 @@ private static final int FIRST_FRAME_OFFSET_MS = 1000 / 60; /** - * Can be used to slow down created animations for debugging purposes. + * Multiplier for animation durations for debugging. Can be set in Developer Options and cached + * here. */ - private static final int ANIMATION_MULTIPLIER = 1; + private static Float sAnimationMultiplier; private final AtomicBoolean mFinishCalled = new AtomicBoolean(); private final ArrayList<Animation<T>> mAnimations = new ArrayList<Animation<T>>(); @@ -256,11 +262,26 @@ mAnimatedObject = t; mStart = start; mEnd = end; - mDuration = duration * ANIMATION_MULTIPLIER; - mStartDelay = startTime * ANIMATION_MULTIPLIER; + float animationMultiplier = getAnimationMultiplier(); + mDuration = (long) (duration * animationMultiplier); + mStartDelay = (long) (startTime * animationMultiplier); mCurrentTime = 0; } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + private float getAnimationMultiplier() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return 1f; + + synchronized (sLock) { + if (sAnimationMultiplier == null) { + sAnimationMultiplier = Settings.Global.getFloat( + ContextUtils.getApplicationContext().getContentResolver(), + Settings.Global.ANIMATOR_DURATION_SCALE, 1f); + } + return sAnimationMultiplier; + } + } + /** * Returns the object being animated. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/GestureEventFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/GestureEventFilter.java index 8b2a49c..62d7714 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/GestureEventFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/eventfilter/GestureEventFilter.java
@@ -84,6 +84,7 @@ public GestureEventFilter(Context context, EventFilterHost host, GestureHandler handler, boolean autoOffset, boolean useDefaultLongPress) { super(context, host, autoOffset); + assert handler != null; mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mLongPressTimeoutMs = ViewConfiguration.getLongPressTimeout(); mUseDefaultLongPress = useDefaultLongPress; @@ -112,7 +113,7 @@ distanceY *= ratio; } } - if (mHandler != null && mSingleInput) { + if (mSingleInput) { // distanceX/Y only represent the distance since the last event, not the total // distance for the full scroll. Calculate the total distance here. float totalX = e2.getX() - mOnScrollBeginX; @@ -130,7 +131,7 @@ * during long press, so we need to explicitly not call handler.click if a * long press has been detected. */ - if (mHandler != null && mSingleInput && !mInLongPress) { + if (mSingleInput && !mInLongPress) { mHandler.click(e.getX() * mPxToDp, e.getY() * mPxToDp, e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE, mButtons); @@ -141,7 +142,7 @@ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (mHandler != null && mSingleInput) { + if (mSingleInput) { mHandler.fling(e1.getX() * mPxToDp, e1.getY() * mPxToDp, velocityX * mPxToDp, velocityY * mPxToDp); } @@ -153,7 +154,7 @@ mButtons = e.getButtonState(); mInLongPress = false; mSeenFirstScrollEvent = false; - if (mHandler != null && mSingleInput) { + if (mSingleInput) { mHandler.onDown(e.getX() * mPxToDp, e.getY() * mPxToDp, e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE, @@ -172,7 +173,7 @@ } private void longPress(MotionEvent e) { - if (mHandler != null && mSingleInput) { + if (mSingleInput) { mInLongPress = true; mHandler.onLongPress(e.getX() * mPxToDp, e.getY() * mPxToDp); } @@ -180,7 +181,7 @@ @Override public boolean onInterceptTouchEventInternal(MotionEvent e, boolean isKeyboardShowing) { - return mHandler != null; + return true; } private void cancelLongPress() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index 1c5364f..a406ac4d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -545,6 +545,7 @@ * Open a link from the panel in a new tab. * @param url The URL to load. */ + @Override public void createNewTab(String url) { if (mChromeActivity == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java index ab4ac0f..0cb4dd0b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java
@@ -81,6 +81,7 @@ super.onButtonClicked(isPrimaryButton); } + @Override @CalledByNative protected boolean isPersistSwitchOn() { return super.isPersistSwitchOn();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java index dcb5015..9b1e0e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java
@@ -173,6 +173,7 @@ return this; } + @Override public ChromeNotificationBuilder setOnlyAlertOnce(boolean onlyAlertOnce) { mBuilder.setOnlyAlertOnce(onlyAlertOnce); return this;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index baf1a596..c833e89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -304,11 +304,7 @@ final TextView searchBoxTextView = (TextView) mSearchBoxView .findViewById(R.id.search_box_text); - boolean isTablet = DeviceFormFactor.isTablet(getContext()); - - // If the Google G should not be shown then clear it because it is shown by default in xml. - if (isTablet - || !ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SHOW_GOOGLE_G_IN_OMNIBOX)) { + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SHOW_GOOGLE_G_IN_OMNIBOX)) { searchBoxTextView.setCompoundDrawablePadding(0); // Not using the relative version of this call because we only want to clear @@ -317,7 +313,7 @@ } String hintText = getResources().getString(R.string.search_or_type_url); - if (!isTablet || mManager.isFakeOmniboxTextEnabledTablet()) { + if (!DeviceFormFactor.isTablet(getContext()) || mManager.isFakeOmniboxTextEnabledTablet()) { searchBoxTextView.setHint(hintText); } else { searchBoxTextView.setContentDescription(hintText); @@ -523,8 +519,7 @@ if (hasLogo == mSearchProviderHasLogo && mInitialized) return; mSearchProviderHasLogo = hasLogo; boolean showLogo = mSearchProviderHasLogo - && (DeviceFormFactor.isTablet(getContext()) - || !ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)); + && !ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT); // Set a bit more top padding on the tile grid if there is no logo. int paddingTop = getResources().getDimensionPixelSize(showLogo
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java index f718dad..2a95de7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -139,6 +139,9 @@ private boolean mIgnoreAutocomplete = true; private boolean mLastUrlEditWasDelete; + /** This tracks whether or not the last ACTION_DOWN event was when the url bar had focus. */ + boolean mDownEventHadFocus; + /** * Implement this to get updates when the direction of the text in the URL bar changes. * E.g. If the user is typing a URL, then erases it and starts typing a query in Arabic, @@ -555,6 +558,8 @@ return true; } + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) mDownEventHadFocus = mFocused; + Tab currentTab = mUrlBarDelegate.getCurrentTab(); if (event.getAction() == MotionEvent.ACTION_DOWN && currentTab != null) { // Make sure to hide the current ContentView ActionBar. @@ -566,6 +571,15 @@ } @Override + public boolean performLongClick(float x, float y) { + // If the touch event that triggered this was when the url bar was in a different focus + // state, ignore the event. + if (mDownEventHadFocus != mFocused) return true; + + return super.performLongClick(x, y); + } + + @Override public boolean bringPointIntoView(int offset) { if (mDisableTextScrollingFromAutocomplete) return false; return super.bringPointIntoView(offset);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java index afe3d31..86ec7157 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java
@@ -194,6 +194,7 @@ .setCustomTitle(titleView) .setNegativeButton(R.string.cancel, this) .setAdapter(mAdapter, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int item) { mCredential = mCredentials[item]; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java index 973494c..0c7fcc02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
@@ -47,6 +47,9 @@ /** The action name for the Pay Intent. */ public static final String ACTION_PAY = "org.chromium.intent.action.PAY"; + /** The maximum number of milliseconds to wait for a response from a READY_TO_PAY service. */ + private static final long READY_TO_PAY_TIMEOUT_MS = 400; + private static final String EXTRA_METHOD_NAME = "methodName"; private static final String EXTRA_DATA = "data"; private static final String EXTRA_ORIGIN = "origin"; @@ -168,6 +171,7 @@ } private void respondToGetInstrumentsQuery(final PaymentInstrument instrument) { + if (mInstrumentsCallback == null) return; mHandler.post(new Runnable() { @Override public void run() { @@ -199,10 +203,17 @@ try { mIsReadyToPayService.isReadyToPay(callback); } catch (Throwable e) { - /** Many undocument exceptions are not caught in the remote Service but passed on to - the Service caller, see writeException in Parcel.java. */ + // Many undocumented exceptions are not caught in the remote Service but passed on to + // the Service caller, see writeException in Parcel.java. respondToGetInstrumentsQuery(null); + return; } + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + respondToGetInstrumentsQuery(null); + } + }, READY_TO_PAY_TIMEOUT_MS); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java index 8a91399..467db90 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
@@ -78,6 +78,7 @@ } /** @return Whether the contact is complete and ready to be sent to the merchant as-is. */ + @Override public boolean isComplete() { return mIsComplete; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java index f2cda58..6530082 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -217,6 +217,7 @@ * @return Whether the card is complete and ready to be sent to the merchant as-is. If true, * this card has a valid card number, a non-empty name on card, and a complete billing address. */ + @Override public boolean isComplete() { return mIsComplete; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 72a7bc0..3c06b63d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -376,6 +376,7 @@ recordSuccessFunnelHistograms("Initiated"); } + @Override protected void finalize() throws Throwable { super.finalize(); if (mCurrencyFormatter != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java index fdaccc7..6ed1ad3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java
@@ -42,6 +42,7 @@ * Helper method to make an HTTP request. * @param urlConnection The HTTP connection. */ + @Override public void writeToUrlConnection(HttpURLConnection urlConnection) throws IOException {} /** @@ -49,6 +50,7 @@ * @param is The InputStream. * @return The decoded image. */ + @Override protected Bitmap readInputStream(InputStream is) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buffer = new byte[1024];
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java index 8b14850..fae2427 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java
@@ -45,6 +45,7 @@ * Helper method to make an HTTP request. * @param urlConnection The HTTP connection. */ + @Override public void writeToUrlConnection(HttpURLConnection urlConnection) throws IOException { urlConnection.setDoOutput(true); urlConnection.setRequestProperty("Content-Type", "application/json"); @@ -60,6 +61,7 @@ * @param is The InputStream. * @return An object representing the HTTP response. */ + @Override protected JSONObject readInputStream(InputStream is) throws IOException { String jsonString = readStreamToString(is); JSONObject jsonObject;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java index 969ff1c..0ef82a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java
@@ -143,6 +143,7 @@ if (mListener == null && sync != null) { mListener = new ProfileSyncService.SyncStateChangedListener() { + @Override public void syncStateChanged() { if (sync.isEngineInitialized()) { mSyncInitialized = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java index 27e43643..61aa7aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java
@@ -12,11 +12,13 @@ super(origin, embedder, isIncognito); } + @Override protected int getNativePreferenceValue(String origin, String embedder, boolean isIncognito) { return WebsitePreferenceBridge.nativeGetCameraSettingForOrigin( origin, embedder, isIncognito); } + @Override protected void setNativePreferenceValue( String origin, String embedder, ContentSetting value, boolean isIncognito) { WebsitePreferenceBridge.nativeSetCameraSettingForOrigin(origin, value.toInt(), isIncognito);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java index 51dd41c..b45498c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java
@@ -12,11 +12,13 @@ super(origin, embedder, isIncognito); } + @Override protected int getNativePreferenceValue(String origin, String embedder, boolean isIncognito) { return WebsitePreferenceBridge.nativeGetMicrophoneSettingForOrigin( origin, embedder, isIncognito); } + @Override protected void setNativePreferenceValue( String origin, String embedder, ContentSetting value, boolean isIncognito) { WebsitePreferenceBridge.nativeSetMicrophoneSettingForOrigin(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java index 1a4eb14..7c059e5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java
@@ -12,10 +12,12 @@ super(origin, embedder, isIncognito); } + @Override protected int getNativePreferenceValue(String origin, String embedder, boolean isIncognito) { return WebsitePreferenceBridge.nativeGetMidiSettingForOrigin(origin, embedder, isIncognito); } + @Override protected void setNativePreferenceValue( String origin, String embedder, ContentSetting value, boolean isIncognito) { WebsitePreferenceBridge.nativeSetMidiSettingForOrigin(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java index e94cd94..a04656e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -77,6 +77,7 @@ mProfileSyncService.addSyncStateChangedListener(this); mProfileSyncService.setMasterSyncEnabledProvider( new ProfileSyncService.MasterSyncEnabledProvider() { + @Override public boolean isMasterSyncEnabled() { return AndroidSyncSettings.isMasterSyncEnabled(mContext); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java index 494538d..5c1b6659 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -5,9 +5,17 @@ package org.chromium.chrome.browser.toolbar; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; import android.util.AttributeSet; +import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; +import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.widget.BottomSheet; import org.chromium.chrome.browser.widget.BottomSheetObserver; @@ -16,6 +24,12 @@ * Phone specific toolbar that exists at the bottom of the screen. */ public class BottomToolbarPhone extends ToolbarPhone implements BottomSheetObserver { + /** The white version of the toolbar handle; used for dark themes and incognito. */ + private final Bitmap mHandleLight; + + /** The dark version of the toolbar handle; this is the default handle to use. */ + private final Bitmap mHandleDark; + /** A handle to the bottom sheet. */ private BottomSheet mBottomSheet; @@ -30,6 +44,9 @@ */ private float mLastHeightFraction; + /** The toolbar handle view that indicates the toolbar can be pulled upward. */ + private ImageView mToolbarHandleView; + /** * Constructs a BottomToolbarPhone object. * @param context The Context in which this View object is created. @@ -37,6 +54,14 @@ */ public BottomToolbarPhone(Context context, AttributeSet attrs) { super(context, attrs); + + int defaultHandleColor = + ApiCompatibilityUtils.getColor(getResources(), R.color.google_grey_500); + mHandleDark = generateHandleBitmap(defaultHandleColor); + + int lightHandleColor = + ApiCompatibilityUtils.getColor(getResources(), R.color.semi_opaque_white); + mHandleLight = generateHandleBitmap(lightHandleColor); } @Override @@ -80,6 +105,90 @@ mProgressBar.setProgressBarContainer(coordinator); } + /** + * @return The extra top margin that should be applied to the browser controls views to + * correctly offset them from the handle that sits above them. + */ + private int getExtraTopMargin() { + return getResources().getDimensionPixelSize(R.dimen.bottom_toolbar_top_margin); + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + + // Programmatically apply a top margin to all the children of the toolbar container. This + // is done so the view hierarchy does not need to be changed. + int topMarginForControls = getExtraTopMargin(); + + View topShadow = findViewById(R.id.bottom_toolbar_shadow); + + for (int i = 0; i < getChildCount(); i++) { + View curView = getChildAt(i); + + // Skip the shadow that sits at the top of the toolbar since this needs to sit on top + // of the toolbar. + if (curView == topShadow) continue; + + ((MarginLayoutParams) curView.getLayoutParams()).topMargin = topMarginForControls; + } + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + // The toolbar handle is part of the control container so it can draw on top of the other + // toolbar views. Get the root view and search for the handle. + mToolbarHandleView = (ImageView) getRootView().findViewById(R.id.toolbar_handle); + mToolbarHandleView.setImageBitmap(mHandleDark); + } + + @Override + protected void updateVisualsForToolbarState() { + super.updateVisualsForToolbarState(); + + // The handle should not show in tab switcher mode. + mToolbarHandleView.setVisibility( + mTabSwitcherState != ToolbarPhone.STATIC_TAB ? View.INVISIBLE : View.VISIBLE); + mToolbarHandleView.setImageBitmap(mUseLightToolbarDrawables ? mHandleLight : mHandleDark); + } + + @Override + protected void updateLocationBarBackgroundBounds(Rect out, VisualState visualState) { + super.updateLocationBarBackgroundBounds(out, visualState); + + // Allow the location bar to expand to the full height of the control container. + out.top -= getExtraTopMargin() * mUrlExpansionPercent; + } + + /** + * Generate the bitmap used as the handle on the toolbar. This indicates that the toolbar can + * be pulled up. + * @return The handle as a bitmap. + */ + private Bitmap generateHandleBitmap(int handleColor) { + int handleWidth = getResources().getDimensionPixelSize(R.dimen.toolbar_handle_width); + int handleHeight = getResources().getDimensionPixelSize(R.dimen.toolbar_handle_height); + + Bitmap handle = Bitmap.createBitmap(handleWidth, handleHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(handle); + + // Clear the canvas to be completely transparent. + canvas.drawARGB(0, 0, 0, 0); + + Paint paint = new Paint(); + paint.setColor(handleColor); + paint.setAntiAlias(true); + + RectF rect = new RectF(0, 0, handleWidth, handleHeight); + + // Use height / 2 for the corner radius so the handle always takes the shape of a pill. + canvas.drawRoundRect(rect, handleHeight / 2f, handleHeight / 2f, paint); + + return handle; + } + @Override protected boolean shouldHideEndToolbarButtons() { return mShouldHideEndToolbarButtons;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java index e06bba2d..a27517aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -167,11 +167,6 @@ } @Override - protected int getToolbarHeightWithoutShadowResId() { - return R.dimen.custom_tabs_control_container_height; - } - - @Override public void initialize(ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController, AppMenuButtonHelper appMenuButtonHelper) { super.initialize(toolbarDataProvider, tabController, appMenuButtonHelper);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java index a6c471fb..fa4c5743 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/Toolbar.java
@@ -36,6 +36,12 @@ void getPositionRelativeToContainer(View containerView, int[] position); /** + * Get the height of the toolbar in px. + * @return The height of the toolbar. + */ + int getHeight(); + + /** * Sets whether or not the toolbar should draw as if it's being captured for a snapshot * texture. In this mode it will only draw the toolbar in it's normal state (no TabSwitcher * or animations).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java index 84a77aa..fa95604 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
@@ -163,7 +163,6 @@ private final View mToolbarContainer; private Toolbar mToolbar; - private int mToolbarActualHeightPx; private int mTabStripHeightPx; /** Builds the resource adapter for the toolbar. */ @@ -178,12 +177,6 @@ */ public void setToolbar(Toolbar toolbar) { mToolbar = toolbar; - int containerHeightResId = R.dimen.control_container_height; - if (mToolbar instanceof CustomTabToolbar) { - containerHeightResId = R.dimen.custom_tabs_control_container_height; - } - mToolbarActualHeightPx = mToolbarContainer.getResources().getDimensionPixelSize( - containerHeightResId); mTabStripHeightPx = mToolbarContainer.getResources().getDimensionPixelSize( R.dimen.tab_strip_height); } @@ -228,8 +221,8 @@ @Override protected void computeContentPadding(Rect outContentPadding) { - outContentPadding.set(0, mTabStripHeightPx, mToolbarContainer.getWidth(), - mToolbarActualHeightPx); + outContentPadding.set( + 0, mTabStripHeightPx, mToolbarContainer.getWidth(), mToolbar.getHeight()); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java index 9855702..20817c0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -77,8 +77,6 @@ private long mFirstDrawTimeMs; - protected final int mToolbarHeightWithoutShadow; - private boolean mFindInPageToolbarShowing; protected boolean mShowMenuBadge; @@ -90,12 +88,24 @@ */ public ToolbarLayout(Context context, AttributeSet attrs) { super(context, attrs); - mToolbarHeightWithoutShadow = getResources().getDimensionPixelOffset( - getToolbarHeightWithoutShadowResId()); mDarkModeTint = ApiCompatibilityUtils.getColorStateList(getResources(), R.color.dark_mode_tint); mLightModeTint = ApiCompatibilityUtils.getColorStateList(getResources(), R.color.light_mode_tint); + + addOnLayoutChangeListener(new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View view, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + // Creation of the progress bar is done here so the toolbar height is available. + mProgressBar = new ToolbarProgressBar(getContext(), getProgressBarTopMargin()); + if (isNativeLibraryReady()) mProgressBar.initializeAnimation(); + addProgressBarToHierarchy(); + + // Since this only needs to happen once, remove this listener from the view. + removeOnLayoutChangeListener(this); + } + }); } /** @@ -104,7 +114,7 @@ * @return The top margin of the progress bar. */ protected int getProgressBarTopMargin() { - return mToolbarHeightWithoutShadow + return getHeight() - getResources().getDimensionPixelSize(R.dimen.toolbar_progress_bar_height); } @@ -112,10 +122,6 @@ protected void onFinishInflate() { super.onFinishInflate(); - mProgressBar = new ToolbarProgressBar(getContext(), getProgressBarTopMargin()); - - if (isNativeLibraryReady()) mProgressBar.initializeAnimation(); - mMenuButton = (TintedImageButton) findViewById(R.id.menu_button); mMenuBadge = (ImageView) findViewById(R.id.menu_badge); mMenuButtonWrapper = findViewById(R.id.menu_button_wrapper); @@ -169,13 +175,6 @@ } /** - * @return The resource id to be used while getting the toolbar height with no shadow. - */ - protected int getToolbarHeightWithoutShadowResId() { - return R.dimen.toolbar_height_no_shadow; - } - - /** * Initialize the external dependencies required for view interaction. * @param toolbarDataProvider The provider for toolbar data. * @param tabController The controller that handles interactions with the tab. @@ -263,12 +262,6 @@ mProgressBar.setProgressBarContainer(controlContainer); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - addProgressBarToHierarchy(); - } - /** * Shows the content description toast for items on the toolbar. * @param view The view to anchor the toast.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java index 328bb77..28b4d730 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -95,10 +95,10 @@ private static final float UNINITIALIZED_PERCENT = -1f; /** States that the toolbar can be in regarding the tab switcher. */ - private static final int STATIC_TAB = 0; - private static final int TAB_SWITCHER = 1; - private static final int ENTERING_TAB_SWITCHER = 2; - private static final int EXITING_TAB_SWITCHER = 3; + protected static final int STATIC_TAB = 0; + protected static final int TAB_SWITCHER = 1; + protected static final int ENTERING_TAB_SWITCHER = 2; + protected static final int EXITING_TAB_SWITCHER = 3; @ViewDebug.ExportedProperty(category = "chrome", mapping = { @ViewDebug.IntToString(from = STATIC_TAB, to = "STATIC_TAB"), @@ -130,7 +130,7 @@ private final List<View> mTabSwitcherModeViews = new ArrayList<>(); private final Set<View> mBrowsingModeViews = new HashSet<>(); @ViewDebug.ExportedProperty(category = "chrome") - private int mTabSwitcherState; + protected int mTabSwitcherState; // This determines whether or not the toolbar draws as expected (false) or whether it always // draws as if it's showing the non-tabswitcher, non-animating toolbar. This is used in grabbing @@ -179,7 +179,7 @@ * maximum of {@link #mUrlFocusChangePercent} and {@link #mNtpSearchBoxScrollPercent}. */ @ViewDebug.ExportedProperty(category = "chrome") - private float mUrlExpansionPercent; + protected float mUrlExpansionPercent; private AnimatorSet mUrlFocusLayoutAnimator; private boolean mDisableLocationBarRelayout; private boolean mLayoutLocationBarInFocusedMode; @@ -248,7 +248,7 @@ /** * Used to specify the visual state of the toolbar. */ - private enum VisualState { + protected enum VisualState { TAB_SWITCHER_INCOGNITO, TAB_SWITCHER_NORMAL, NORMAL, @@ -259,7 +259,7 @@ private VisualState mVisualState = VisualState.NORMAL; private VisualState mOverlayDrawablesVisualState; - private boolean mUseLightToolbarDrawables; + protected boolean mUseLightToolbarDrawables; private NewTabPage mVisibleNewTabPage; private float mPreTextureCaptureAlpha = 1f; @@ -738,7 +738,7 @@ /** * Calculate the bounds for the location bar background and set them to {@code out}. */ - private void updateLocationBarBackgroundBounds(Rect out, VisualState visualState) { + protected void updateLocationBarBackgroundBounds(Rect out, VisualState visualState) { // Calculate the visible boundaries of the left and right most child views of the // location bar. float expansion = visualState == VisualState.NEW_TAB_NORMAL ? 1 : mUrlExpansionPercent; @@ -1237,7 +1237,7 @@ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mBackgroundOverlayBounds.set(0, 0, w, mToolbarHeightWithoutShadow); + mBackgroundOverlayBounds.set(0, 0, w, h); super.onSizeChanged(w, h, oldw, oldh); } @@ -1539,7 +1539,8 @@ ApiCompatibilityUtils.getColor(getResources(), android.R.color.transparent)); } else { TypedValue outValue = new TypedValue(); - // the linked style here will have to be changed if it is updated in the XML. + + // The linked style here will have to be changed if it is updated in the XML. getContext().getTheme().resolveAttribute(R.style.ToolbarButton, outValue, true); mToggleTabStackButton.setBackgroundResource(outValue.resourceId); } @@ -2022,7 +2023,7 @@ return VisualState.NORMAL; } - private void updateVisualsForToolbarState() { + protected void updateVisualsForToolbarState() { final boolean isIncognito = isIncognito(); // These are important for setting visual state while the entering or leaving the tab
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java index 36745ee01..9c411d3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java
@@ -61,12 +61,14 @@ } ShareHelper.TargetChosenCallback innerCallback = new ShareHelper.TargetChosenCallback() { + @Override public void onTargetChosen(ComponentName chosenComponent) { RecordHistogram.recordEnumeratedHistogram("WebShare.ShareOutcome", WEBSHARE_OUTCOME_SUCCESS, WEBSHARE_OUTCOME_COUNT); callback.call(ShareError.OK); } + @Override public void onCancel() { RecordHistogram.recordEnumeratedHistogram("WebShare.ShareOutcome", WEBSHARE_OUTCOME_CANCELED, WEBSHARE_OUTCOME_COUNT);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java index 5a235403..940914f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -352,6 +352,7 @@ // Listen to height changes on the root. root.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { // Make sure the size of the layout actually changed. @@ -370,6 +371,7 @@ // Listen to height changes on the toolbar. controlContainer.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { // Make sure the size of the layout actually changed.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index f751f02..99652c59 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -409,7 +409,7 @@ Auto Sign-in </message> <message name="IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC" desc="Text that describes the 'Auto Sign-in' functionality to users."> - Automatically sign in to websites using stored credentials. When the feature is disabled, you will be asked for confirmation every time before signing in to a website. + Automatically sign in to websites using stored credentials. If disabled, you will be asked for confirmation every time before signing in to a website. </message> <message name="IDS_SETTINGS_PASSWORDS_DETAIL" desc="Description of what toggling the 'Manage passwords' setting does. Immediately underneath IDS_SETTINGS_PASSWORDS"> Offer to save your web passwords
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d8af69c..6f25337 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -804,6 +804,8 @@ "page_load_metrics/observers/https_engagement_metrics/https_engagement_service.h", "page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc", "page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h", + "page_load_metrics/observers/media_page_load_metrics_observer.cc", + "page_load_metrics/observers/media_page_load_metrics_observer.h", "page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.cc", "page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h", "page_load_metrics/observers/prerender_page_load_metrics_observer.cc", @@ -858,8 +860,6 @@ "performance_monitor/process_metrics_history.h", "permissions/chooser_context_base.cc", "permissions/chooser_context_base.h", - "permissions/delegation_tracker.cc", - "permissions/delegation_tracker.h", "permissions/permission_blacklist_client.cc", "permissions/permission_blacklist_client.h", "permissions/permission_context_base.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 88f243a..e78f8901 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -143,6 +143,10 @@ const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS | kOsAndroid; const unsigned kOsDesktop = kOsMac | kOsWin | kOsLinux | kOsCrOS; +#if defined(USE_AURA) +const unsigned kOsAura = kOsWin | kOsLinux | kOsCrOS; +#endif // USE_AURA + const FeatureEntry::Choice kTouchEventFeatureDetectionChoices[] = { { IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC, "", "" }, { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED, @@ -870,15 +874,15 @@ kOsLinux | kOsCrOS | kOsWin | kOsAndroid, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSmoothScrolling, switches::kDisableSmoothScrolling)}, -#if defined(USE_AURA) || defined(OS_LINUX) +#if defined(USE_AURA) {"overlay-scrollbars", IDS_FLAGS_OVERLAY_SCROLLBARS_NAME, IDS_FLAGS_OVERLAY_SCROLLBARS_DESCRIPTION, // Uses the system preference on Mac (a different implementation). // On Android, this is always enabled. - kOsLinux | kOsCrOS | kOsWin, + kOsAura, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOverlayScrollbar, switches::kDisableOverlayScrollbar)}, -#endif // USE_AURA || OS_LINUX +#endif // USE_AURA { // See http://crbug.com/120416 for how to remove this flag. "save-page-as-mhtml", IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME, IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION, kOsMac | kOsWin | kOsLinux, @@ -1138,7 +1142,7 @@ #if defined(USE_AURA) {"overscroll-history-navigation", IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME, - IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION, kOsAll, + IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION, kOsAura, MULTI_VALUE_TYPE(kOverscrollHistoryNavigationChoices)}, #endif // USE_AURA {"scroll-end-effect", IDS_FLAGS_SCROLL_END_EFFECT_NAME,
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc index dd439fb..58671d23 100644 --- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -36,15 +36,18 @@ #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/text_input_test_utils.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/test/extension_test_message_listener.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "ui/base/ime/composition_text.h" +#include "ui/base/ime/composition_underline.h" #include "ui/base/ime/text_input_client.h" #include "ui/base/test/ui_controls.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/range/range.h" using extensions::AppWindow; using extensions::ExtensionsAPIClient; @@ -517,6 +520,7 @@ class WebViewNewWindowInteractiveTest : public WebViewInteractiveTest {}; class WebViewFocusInteractiveTest : public WebViewInteractiveTest {}; class WebViewPointerLockInteractiveTest : public WebViewInteractiveTest {}; +class WebViewImeInteractiveTest : public WebViewInteractiveTest {}; // The tests below aren't needed in --use-cross-process-frames-for-guests. class WebViewContextMenuInteractiveTest : public WebViewInteractiveTestBase {}; @@ -546,6 +550,10 @@ WebViewPointerLockInteractiveTest, testing::Bool()); +INSTANTIATE_TEST_CASE_P(WebViewInteractiveTests, + WebViewImeInteractiveTest, + testing::Bool()); + // ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and // likely won't work on many other platforms as well, so for now this test // is for Windows and Linux only. As of Sept 17th, 2013 this test is disabled @@ -1507,3 +1515,66 @@ ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); } + +#if defined(OS_MACOSX) +// This test verifies that replacement range for IME works with <webview>s. To +// verify this, a <webview> with an <input> inside is loaded. Then the <input> +// is focused and populated with some text. The test then sends an IPC to +// commit some text which will replace part of the previous text some new text. +IN_PROC_BROWSER_TEST_P(WebViewImeInteractiveTest, + CommitTextWithReplacementRange) { + ASSERT_TRUE(StartEmbeddedTestServer()); // For serving guest pages. + LoadAndLaunchPlatformApp("web_view/ime", "WebViewImeTest.Launched"); + ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())); + + // Flush any pending events to make sure we start with a clean slate. + content::RunAllPendingInMessageLoop(); + + content::WebContents* guest_web_contents = + GetGuestViewManager()->GetLastGuestCreated(); + + // Click the <input> element inside the <webview>. In its focus handle, the + // <input> inside the <webview> initializes its value to "A B X D". + ExtensionTestMessageListener focus_listener("WebViewImeTest.InputFocused", + false); + content::WebContents* target_web_contents = + GetParam() + ? guest_web_contents + : guest_view::GuestViewBase::FromWebContents(guest_web_contents) + ->embedder_web_contents(); + content::SimulateMouseClickAt(target_web_contents, 0, + blink::WebMouseEvent::Button::Left, + gfx::Point(50, 50)); + focus_listener.WaitUntilSatisfied(); + + // Verify the text inside the <input> is "A B X D". + std::string value; + ASSERT_TRUE(ExecuteScriptAndExtractString(guest_web_contents, + "window.domAutomationController." + "send(document.querySelector('" + "input').value)", + &value)); + EXPECT_EQ("A B X D", value); + + // Now commit "C" to to replace the range (4, 5). + // For OOPIF guests, the target for IME is the RWH for the guest's main frame. + // For BrowserPlugin-based guests, input always goes to the embedder. + ExtensionTestMessageListener input_listener("WebViewImetest.InputReceived", + false); + content::RenderWidgetHost* target_rwh_for_input = + target_web_contents->GetRenderWidgetHostView()->GetRenderWidgetHost(); + content::SendImeCommitTextToWidget( + target_rwh_for_input, base::UTF8ToUTF16("C"), + std::vector<ui::CompositionUnderline>(), gfx::Range(4, 5), 0); + input_listener.WaitUntilSatisfied(); + + // Get the input value from the guest. + value.clear(); + ASSERT_TRUE(ExecuteScriptAndExtractString(guest_web_contents, + "window.domAutomationController." + "send(document.querySelector('" + "input').value)", + &value)); + EXPECT_EQ("A B C D", value); +} +#endif // OS_MACOSX
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 8878bb27..3ad22f3 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -200,7 +200,6 @@ #include "base/trace_event/trace_event_etw_export_win.h" #include "base/win/registry.h" #include "base/win/win_util.h" -#include "base/win/windows_version.h" #include "chrome/browser/chrome_browser_main_win.h" #include "chrome/browser/component_updater/sw_reporter_installer_win.h" #include "chrome/browser/downgrade/user_data_downgrade.h" @@ -1706,10 +1705,7 @@ // This could be run as late as WM_QUERYENDSESSION for system update reboots, // but should run on startup if extended to handle crashes/hangs/patches. // Also, better to run once here than once for each HWND's WM_QUERYENDSESSION. - if (base::win::GetVersion() >= base::win::VERSION_VISTA) { - ChromeBrowserMainPartsWin::RegisterApplicationRestart( - parsed_command_line()); - } + ChromeBrowserMainPartsWin::RegisterApplicationRestart(parsed_command_line()); // Verify that the profile is not on a network share and if so prepare to show // notification to the user.
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index cd155a0b..631afa0b 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc
@@ -425,7 +425,6 @@ // static void ChromeBrowserMainPartsWin::RegisterApplicationRestart( const base::CommandLine& parsed_command_line) { - DCHECK(base::win::GetVersion() >= base::win::VERSION_VISTA); base::ScopedNativeLibrary library(base::FilePath(L"kernel32.dll")); // Get the function pointer for RegisterApplicationRestart. RegisterApplicationRestartProc register_application_restart = @@ -444,15 +443,17 @@ // Restart Chrome if the computer is restarted as the result of an update. // This could be extended to handle crashes, hangs, and patches. + const auto& command_line_string = command_line.GetCommandLineString(); HRESULT hr = register_application_restart( - command_line.GetCommandLineString().c_str(), + command_line_string.c_str(), RESTART_NO_CRASH | RESTART_NO_HANG | RESTART_NO_PATCH); if (FAILED(hr)) { if (hr == E_INVALIDARG) { - LOG(WARNING) << "Command line too long for RegisterApplicationRestart"; + LOG(WARNING) << "Command line too long for RegisterApplicationRestart: " + << command_line_string; } else { - NOTREACHED() << "RegisterApplicationRestart failed. hr: " << hr << - ", command_line: " << command_line.GetCommandLineString(); + NOTREACHED() << "RegisterApplicationRestart failed. hr: " << hr + << ", command_line: " << command_line_string; } } }
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc index 4caff1f5..48085cf 100644 --- a/chrome/browser/chromeos/input_method/input_method_util.cc +++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -79,6 +79,9 @@ // The engine ID map for migration. This migration is for input method IDs from // VPD so it's NOT a temporary migration. const char* const kEngineIdMigrationMap[][2] = { + // Workaround for invalid keyboard layout in kefka board vpd. + // See https://crbug.com/700625 + {"ANSI", "xkb:us::eng"}, {"ime:jp:mozc_jp", "nacl_mozc_jp"}, {"ime:jp:mozc_us", "nacl_mozc_us"}, {"ime:ko:hangul_2set", "ko-t-i0-und"},
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc index 8444d612..b074a04 100644 --- a/chrome/browser/chromeos/login/login_browsertest.cc +++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -181,7 +181,7 @@ // Used to make sure that the system tray is visible and within the screen // bounds after login. -void TestSystemTrayIsVisible() { +void TestSystemTrayIsVisible(bool otr) { ash::SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray(); aura::Window* primary_win = ash::Shell::GetPrimaryRootWindow(); ash::WmWindow* wm_primary_win = ash::WmWindow::Get(primary_win); @@ -190,7 +190,10 @@ << "ShelfVisibilityState=" << wm_shelf->GetVisibilityState() << " ShelfAutoHideBehavior=" << wm_shelf->auto_hide_behavior()); EXPECT_TRUE(tray->visible()); - EXPECT_TRUE(RectContains(primary_win->bounds(), tray->GetBoundsInScreen())); + + // This check flakes for LoginGuestTest: https://crbug.com/693106. + if (!otr) + EXPECT_TRUE(RectContains(primary_win->bounds(), tray->GetBoundsInScreen())); } } // namespace @@ -205,33 +208,31 @@ EXPECT_EQ(profile_base_path, profile->GetPath().BaseName().value()); EXPECT_FALSE(profile->IsOffTheRecord()); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(false); } // Verifies the cursor is not hidden at startup when user is logged in. IN_PROC_BROWSER_TEST_F(LoginUserTest, CursorShown) { EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible()); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(false); } // After a guest login, we should get the OTR default profile. -// Test is flaky https://crbug.com/693106 -IN_PROC_BROWSER_TEST_F(LoginGuestTest, DISABLED_GuestIsOTR) { +IN_PROC_BROWSER_TEST_F(LoginGuestTest, GuestIsOTR) { Profile* profile = browser()->profile(); EXPECT_TRUE(profile->IsOffTheRecord()); // Ensure there's extension service for this profile. EXPECT_TRUE(extensions::ExtensionSystem::Get(profile)->extension_service()); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(true); } // Verifies the cursor is not hidden at startup when running guest session. -// Test is flaky https://crbug.com/693106 -IN_PROC_BROWSER_TEST_F(LoginGuestTest, DISABLED_CursorShown) { +IN_PROC_BROWSER_TEST_F(LoginGuestTest, CursorShown) { EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible()); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(true); } // Verifies the cursor is hidden at startup on login screen. @@ -249,7 +250,7 @@ base::ThreadTaskRunnerHandle::Get()->DeleteSoon( FROM_HERE, LoginDisplayHost::default_host()); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(false); } // Verifies that the webui for login comes up successfully. @@ -276,7 +277,7 @@ SubmitGaiaAuthOfflineForm(kTestUser, kPassword); session_start_waiter.Wait(); - TestSystemTrayIsVisible(); + TestSystemTrayIsVisible(false); } } // namespace chromeos
diff --git a/chrome/browser/content_settings/chrome_content_settings_utils.h b/chrome/browser/content_settings/chrome_content_settings_utils.h index 650103f47..50429a6 100644 --- a/chrome/browser/content_settings/chrome_content_settings_utils.h +++ b/chrome/browser/content_settings/chrome_content_settings_utils.h
@@ -47,6 +47,8 @@ POPUPS_ACTION_SELECTED_ALWAYS_ALLOW_POPUPS_FROM, POPUPS_ACTION_CLICKED_LIST_ITEM_CLICKED, POPUPS_ACTION_CLICKED_MANAGE_POPUPS_BLOCKING, + POPUPS_ACTION_DISPLAYED_INFOBAR_ON_MOBILE, + POPUPS_ACTION_CLICKED_ALWAYS_SHOW_ON_MOBILE, POPUPS_ACTION_COUNT };
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc index 82a5940d..8d9c2d29 100644 --- a/chrome/browser/download/download_request_limiter_unittest.cc +++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -29,7 +29,7 @@ #else #include "chrome/browser/download/download_permission_request.h" #include "chrome/browser/permissions/permission_request_manager.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #endif using content::WebContents;
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc index 479e108..d019e8e5 100644 --- a/chrome/browser/extensions/extension_disabled_ui.cc +++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -163,17 +163,7 @@ content::Source<Profile>(service->profile())); } -ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() { - if (is_remote_install_) { - UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponseRemoteInstall", - user_response_, - EXTENSION_DISABLED_UI_BUCKET_BOUNDARY); - } else { - UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponse", - user_response_, - EXTENSION_DISABLED_UI_BUCKET_BOUNDARY); - } -} +ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() {} GlobalError::Severity ExtensionDisabledGlobalError::GetSeverity() { return SEVERITY_LOW; @@ -276,6 +266,19 @@ } void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) { + // If the user takes an action, |user_response_| is set in + // BubbleView[Cancel|Accept]Pressed(). Otherwise, the IGNORE value set in the + // constructor is correct. + UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponseRemoteInstall2", + user_response_, + EXTENSION_DISABLED_UI_BUCKET_BOUNDARY); + UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponse2", + user_response_, + EXTENSION_DISABLED_UI_BUCKET_BOUNDARY); + // Reset in case the user does not follow through on subsequent dialogs to + // confirm removal decision, in which case the bubble can be shown again + // when the user clicks on the global error in the menu. + user_response_ = IGNORED; } void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed( @@ -284,6 +287,7 @@ service_->profile())) { return; } + user_response_ = REENABLE; // Delay extension reenabling so this bubble closes properly. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -298,9 +302,9 @@ // Supervised users may never remove custodian-installed extensions. DCHECK(!extensions::util::IsExtensionSupervised(extension_, service_->profile())); - uninstall_dialog_.reset(extensions::ExtensionUninstallDialog::Create( service_->profile(), browser->window()->GetNativeWindow(), this)); + user_response_ = UNINSTALL; // Delay showing the uninstall dialog, so that this function returns // immediately, to close the bubble properly. See crbug.com/121544. base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -341,7 +345,6 @@ const Extension* extension = content::Details<const Extension>(details).ptr(); if (extension != extension_) return; - user_response_ = UNINSTALL; RemoveGlobalError(); } @@ -350,7 +353,6 @@ const Extension* extension) { if (extension != extension_) return; - user_response_ = REENABLE; RemoveGlobalError(); }
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc index ad91455c..b1c8ae3 100644 --- a/chrome/browser/extensions/extension_override_apitest.cc +++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -17,10 +17,14 @@ #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" #include "extensions/common/constants.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/embedded_test_server.h" using content::WebContents; @@ -191,6 +195,43 @@ SchemeIs(kExtensionScheme)); } +// Check that when an overridden new tab page has focus, a subframe navigation +// on that page does not steal the focus away by focusing the omnibox. +// See https://crbug.com/700124. +IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, + SubframeNavigationInOverridenNTPDoesNotAffectFocus) { + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->Start()); + + // Load an extension that overrides the new tab page. + const Extension* extension = LoadExtension(data_dir().AppendASCII("newtab")); + + // Navigate to the new tab page. The overridden new tab page + // will call chrome.test.sendMessage('controlled by first'). + ExtensionTestMessageListener listener("controlled by first", false); + ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL)); + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(ExtensionControlsPage(contents, extension->id())); + EXPECT_TRUE(listener.WaitUntilSatisfied()); + + // Start off with the main page focused. + contents->Focus(); + EXPECT_TRUE(contents->GetRenderWidgetHostView()->HasFocus()); + + // Inject an iframe and navigate it to a cross-site URL. With + // --site-per-process, this will go into a separate process. + GURL cross_site_url(embedded_test_server()->GetURL("a.com", "/title1.html")); + std::string script = "var f = document.createElement('iframe');\n" + "f.src = '" + cross_site_url.spec() + "';\n" + "document.body.appendChild(f);\n"; + EXPECT_TRUE(ExecuteScript(contents, script)); + WaitForLoadStop(contents); + + // The page should still have focus. The cross-process subframe navigation + // above should not try to focus the omnibox, which would make this false. + EXPECT_TRUE(contents->GetRenderWidgetHostView()->HasFocus()); +} + // Times out consistently on Win, http://crbug.com/45173. #if defined(OS_WIN) #define MAYBE_OverrideHistory DISABLED_OverrideHistory
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc index 5f13e59..13845b55 100644 --- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc +++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -62,7 +62,7 @@ #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" #else #include "chrome/browser/permissions/permission_request_manager.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #endif #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/media/cast_remoting_sender.cc b/chrome/browser/media/cast_remoting_sender.cc index 00de025..7a55a9114 100644 --- a/chrome/browser/media/cast_remoting_sender.cc +++ b/chrome/browser/media/cast_remoting_sender.cc
@@ -92,7 +92,7 @@ latest_acked_frame_id_(media::cast::FrameId::first() - 1), duplicate_ack_counter_(0), input_queue_discards_remaining_(0), - pipe_watcher_(FROM_HERE), + pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL), flow_restart_pending_(true), weak_factory_(this) { // Confirm this constructor is running on the IO BrowserThread. @@ -164,10 +164,11 @@ sender->error_callback_ = error_callback; sender->pipe_ = std::move(pipe); - sender->pipe_watcher_.Start( - sender->pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE, - base::Bind(&CastRemotingSender::ProcessInputQueue, - base::Unretained(sender))); + sender->pipe_watcher_.Watch(sender->pipe_.get(), + MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, + base::Bind(&CastRemotingSender::ProcessInputQueue, + base::Unretained(sender))); + sender->pipe_watcher_.ArmOrNotify(); sender->binding_.Bind(std::move(request)); sender->binding_.set_connection_error_handler(sender->error_callback_); } @@ -378,8 +379,10 @@ MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE); if (result == MOJO_RESULT_OK) return true; // Successfully discarded data. - if (result == MOJO_RESULT_OUT_OF_RANGE) + if (result == MOJO_RESULT_OUT_OF_RANGE) { + pipe_watcher_.ArmOrNotify(); return false; // Retry later. + } LOG(ERROR) << SENDER_SSRC << "Unexpected result when discarding from data pipe (" << result << ')'; @@ -395,8 +398,10 @@ MOJO_READ_DATA_FLAG_ALL_OR_NONE); if (result == MOJO_RESULT_OK) return true; // Successfully consumed data. - if (result == MOJO_RESULT_OUT_OF_RANGE) + if (result == MOJO_RESULT_OUT_OF_RANGE) { + pipe_watcher_.ArmOrNotify(); return false; // Retry later. + } LOG(ERROR) << SENDER_SSRC << "Read from data pipe failed (" << result << ')'; } while (false);
diff --git a/chrome/browser/media/cast_remoting_sender.h b/chrome/browser/media/cast_remoting_sender.h index 0228d79..9b177633 100644 --- a/chrome/browser/media/cast_remoting_sender.h +++ b/chrome/browser/media/cast_remoting_sender.h
@@ -15,7 +15,7 @@ #include "media/cast/net/rtcp/rtcp_defines.h" #include "media/mojo/interfaces/remoting.mojom.h" #include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace cast { @@ -196,7 +196,7 @@ // Watches |pipe_| for more data to become available, and then calls // ProcessInputQueue(). - mojo::Watcher pipe_watcher_; + mojo::SimpleWatcher pipe_watcher_; // Set to true if the first frame has not yet been sent, or if a // CancelInFlightData() operation just completed. This causes TrySendFrame()
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.h b/chrome/browser/media/webrtc/media_stream_devices_controller.h index 1777cd9..059ed42d 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller.h +++ b/chrome/browser/media/webrtc/media_stream_devices_controller.h
@@ -28,6 +28,10 @@ class MediaStreamDevicesControllerBrowserTest; } +namespace test { +class MediaStreamDevicesControllerTestApi; +} + class MediaStreamDevicesController : public PermissionRequest { public: static void RequestPermissions( @@ -67,6 +71,7 @@ private: friend class MediaStreamDevicesControllerTest; + friend class test::MediaStreamDevicesControllerTestApi; friend class policy::MediaStreamDevicesControllerBrowserTest; // Delegate showing permission prompts.
diff --git a/chrome/browser/media/webrtc/webrtc_webcam_browsertest.cc b/chrome/browser/media/webrtc/webrtc_webcam_browsertest.cc index 003dd20..49665dd 100644 --- a/chrome/browser/media/webrtc/webrtc_webcam_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_webcam_browsertest.cc
@@ -18,10 +18,6 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest-param-test.h" -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - static const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html"; @@ -93,17 +89,6 @@ GetUserMediaAndGetStreamSize(tab, kVideoCallConstraintsVGA)); EXPECT_EQ("640x360", GetUserMediaAndGetStreamSize(tab, kVideoCallConstraints360p)); - -// TODO(chfremer): Reenable these tests when https://crbug.com/676041 is -// resolved. -#if defined(OS_WIN) - auto win_version = base::win::GetVersion(); - if (win_version == base::win::VERSION_WIN8 || - win_version == base::win::VERSION_WIN8_1) { - return; - } -#endif - EXPECT_EQ("1280x720", GetUserMediaAndGetStreamSize(tab, kVideoCallConstraints720p)); EXPECT_EQ("1920x1080",
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc index 17118cbf6..3aa27449b 100644 --- a/chrome/browser/memory_details.cc +++ b/chrome/browser/memory_details.cc
@@ -94,8 +94,9 @@ : pid(0), num_processes(0), process_type(content::PROCESS_TYPE_UNKNOWN), - renderer_type(RENDERER_UNKNOWN) { -} + num_open_fds(-1), + open_fds_soft_limit(-1), + renderer_type(RENDERER_UNKNOWN) {} ProcessMemoryInformation::ProcessMemoryInformation( const ProcessMemoryInformation& other) = default; @@ -181,6 +182,10 @@ log += StringPrintf(", %d MB swapped", static_cast<int>(iter1->working_set.swapped) / 1024); #endif + if (iter1->num_open_fds != -1 || iter1->open_fds_soft_limit != -1) { + log += StringPrintf(", %d FDs open of %d", iter1->num_open_fds, + iter1->open_fds_soft_limit); + } log += "\n"; } return log;
diff --git a/chrome/browser/memory_details.h b/chrome/browser/memory_details.h index 7cd017d..6ad23e7 100644 --- a/chrome/browser/memory_details.h +++ b/chrome/browser/memory_details.h
@@ -61,6 +61,10 @@ int num_processes; // If this is a child process of Chrome, what type (i.e. plugin) it is. int process_type; + // Number of open file descriptors in this process. + int num_open_fds; + // Maximum number of file descriptors that can be opened in this process. + int open_fds_soft_limit; // If this is a renderer process, what type it is. RendererProcessType renderer_type; // A collection of titles used, i.e. for a tab it'll show all the page titles.
diff --git a/chrome/browser/memory_details_android.cc b/chrome/browser/memory_details_android.cc index 649948b6..aed8fe1a 100644 --- a/chrome/browser/memory_details_android.cc +++ b/chrome/browser/memory_details_android.cc
@@ -63,6 +63,8 @@ std::unique_ptr<base::ProcessMetrics> metrics( base::ProcessMetrics::CreateProcessMetrics(*i)); metrics->GetWorkingSetKBytes(&pmi.working_set); + // TODO(dcastagna): Compute number of open fds (pmi.num_open_fds) and soft + // limits (pmi.open_fds_soft_limit) on android. out->processes.push_back(pmi); }
diff --git a/chrome/browser/memory_details_linux.cc b/chrome/browser/memory_details_linux.cc index ce5f426e..a7f4c544 100644 --- a/chrome/browser/memory_details_linux.cc +++ b/chrome/browser/memory_details_linux.cc
@@ -71,6 +71,8 @@ std::unique_ptr<base::ProcessMetrics> metrics( base::ProcessMetrics::CreateProcessMetrics(pid)); metrics->GetWorkingSetKBytes(&pmi.working_set); + pmi.num_open_fds = metrics->GetOpenFdCount(); + pmi.open_fds_soft_limit = metrics->GetOpenFdSoftLimit(); process_data.processes.push_back(pmi); }
diff --git a/chrome/browser/metrics/metrics_memory_details.cc b/chrome/browser/metrics/metrics_memory_details.cc index 807bc09..cea3e27 100644 --- a/chrome/browser/metrics/metrics_memory_details.cc +++ b/chrome/browser/metrics/metrics_memory_details.cc
@@ -91,26 +91,45 @@ size_t committed = browser.processes[index].committed.priv + browser.processes[index].committed.mapped + browser.processes[index].committed.image; + int num_open_fds = browser.processes[index].num_open_fds; + int open_fds_soft_limit = browser.processes[index].open_fds_soft_limit; aggregate_memory += sample; switch (browser.processes[index].process_type) { case content::PROCESS_TYPE_BROWSER: UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.Large2", sample / 1024); UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.Committed", committed / 1024); + if (num_open_fds != -1 && open_fds_soft_limit != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.Browser.OpenFDs", num_open_fds); + UMA_HISTOGRAM_COUNTS_10000("Memory.Browser.OpenFDsSoftLimit", + open_fds_soft_limit); + } continue; case content::PROCESS_TYPE_RENDERER: { UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.RendererAll", sample / 1024); UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.RendererAll.Committed", committed / 1024); + if (num_open_fds != -1 && open_fds_soft_limit != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.RendererAll.OpenFDs", + num_open_fds); + UMA_HISTOGRAM_COUNTS_10000("Memory.RendererAll.OpenFDsSoftLimit", + open_fds_soft_limit); + } ProcessMemoryInformation::RendererProcessType renderer_type = browser.processes[index].renderer_type; switch (renderer_type) { case ProcessMemoryInformation::RENDERER_EXTENSION: UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.Extension.OpenFDs", + num_open_fds); + } extension_count++; continue; case ProcessMemoryInformation::RENDERER_CHROME: UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); + if (num_open_fds != -1) + UMA_HISTOGRAM_COUNTS_10000("Memory.Chrome.OpenFDs", num_open_fds); chrome_count++; continue; case ProcessMemoryInformation::RENDERER_UNKNOWN: @@ -123,24 +142,41 @@ sample / 1024); UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Renderer.Committed", committed / 1024); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.Renderer.OpenFDs", + num_open_fds); + } renderer_count++; continue; } } case content::PROCESS_TYPE_UTILITY: UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); + if (num_open_fds != -1) + UMA_HISTOGRAM_COUNTS_10000("Memory.Utility.OpenFDs", num_open_fds); other_count++; continue; case content::PROCESS_TYPE_ZYGOTE: UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); + if (num_open_fds != -1) + UMA_HISTOGRAM_COUNTS_10000("Memory.Zygote.OpenFDs", num_open_fds); other_count++; continue; case content::PROCESS_TYPE_SANDBOX_HELPER: UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.SandboxHelper.OpenFDs", + num_open_fds); + } other_count++; continue; case content::PROCESS_TYPE_GPU: UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); + if (num_open_fds != -1 && open_fds_soft_limit != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.Gpu.OpenFDs", num_open_fds); + UMA_HISTOGRAM_COUNTS_10000("Memory.Gpu.OpenFDsSoftLimit", + open_fds_soft_limit); + } other_count++; continue; #if BUILDFLAG(ENABLE_PLUGINS) @@ -152,20 +188,36 @@ UMA_HISTOGRAM_MEMORY_KB("Memory.PepperFlashPlugin", sample); } UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.PepperPlugin.OpenFDs", + num_open_fds); + } pepper_plugin_count++; continue; } case content::PROCESS_TYPE_PPAPI_BROKER: UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.PepperPluginBroker.OpenFDs", + num_open_fds); + } pepper_plugin_broker_count++; continue; #endif case PROCESS_TYPE_NACL_LOADER: UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.NativeClient.OpenFDs", + num_open_fds); + } other_count++; continue; case PROCESS_TYPE_NACL_BROKER: UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); + if (num_open_fds != -1) { + UMA_HISTOGRAM_COUNTS_10000("Memory.NativeClientBroker.OpenFDs", + num_open_fds); + } other_count++; continue; default:
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc b/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc index fd5cf78..1ea9d129 100644 --- a/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc +++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc
@@ -21,6 +21,7 @@ #include "components/variations/variations_associated_data.h" #include "content/public/browser/browser_thread.h" #include "net/nqe/network_qualities_prefs_manager.h" +#include "net/nqe/network_quality.h" namespace { @@ -145,9 +146,9 @@ UINetworkQualityEstimatorService::UINetworkQualityEstimatorService( Profile* profile) : type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN), - http_rtt_(base::TimeDelta::FromMilliseconds(-1)), - transport_rtt_(base::TimeDelta::FromMilliseconds(-1)), - downstream_throughput_kbps_(-1), + http_rtt_(net::nqe::internal::InvalidRTT()), + transport_rtt_(net::nqe::internal::InvalidRTT()), + downstream_throughput_kbps_(net::nqe::internal::kInvalidThroughput), weak_factory_(this) { DCHECK(profile); // If this is running in a context without an IOThread, don't try to create @@ -239,6 +240,33 @@ effective_connection_type_observer_list_.RemoveObserver(observer); } +base::Optional<base::TimeDelta> UINetworkQualityEstimatorService::GetHttpRTT() + const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (http_rtt_ == net::nqe::internal::InvalidRTT()) + return base::Optional<base::TimeDelta>(); + return http_rtt_; +} + +base::Optional<base::TimeDelta> +UINetworkQualityEstimatorService::GetTransportRTT() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (transport_rtt_ == net::nqe::internal::InvalidRTT()) + return base::Optional<base::TimeDelta>(); + return transport_rtt_; +} + +base::Optional<int32_t> +UINetworkQualityEstimatorService::GetDownstreamThroughputKbps() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (downstream_throughput_kbps_ == net::nqe::internal::kInvalidThroughput) + return base::Optional<int32_t>(); + return downstream_throughput_kbps_; +} + void UINetworkQualityEstimatorService::AddRTTAndThroughputEstimatesObserver( net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service.h b/chrome/browser/net/nqe/ui_network_quality_estimator_service.h index af77188b..128456a 100644 --- a/chrome/browser/net/nqe/ui_network_quality_estimator_service.h +++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_NET_NQE_UI_NETWORK_QUALITY_ESTIMATOR_SERVICE_H_ #define CHROME_BROWSER_NET_NQE_UI_NETWORK_QUALITY_ESTIMATOR_SERVICE_H_ +#include <stdint.h> + #include <map> #include <memory> @@ -46,6 +48,9 @@ void RemoveEffectiveConnectionTypeObserver( net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) override; + base::Optional<base::TimeDelta> GetHttpRTT() const override; + base::Optional<base::TimeDelta> GetTransportRTT() const override; + base::Optional<int32_t> GetDownstreamThroughputKbps() const override; // Must be called on the UI thread. |observer| will be notified on the UI // thread. |observer| would be notified of the changes in the HTTP RTT,
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc b/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc index e4119d5..72d41e60 100644 --- a/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc +++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc
@@ -257,11 +257,19 @@ nqe_test_util::OverrideRTTsAndWait(rtt_1); EXPECT_EQ(rtt_1, nqe_observer.http_rtt()); + EXPECT_EQ(rtt_1, nqe_service->GetHttpRTT()); + EXPECT_EQ(rtt_1, nqe_service->GetTransportRTT()); + EXPECT_FALSE(nqe_service->GetDownstreamThroughputKbps().has_value()); + base::TimeDelta rtt_2 = base::TimeDelta::FromMilliseconds(200); nqe_test_util::OverrideRTTsAndWait(rtt_2); EXPECT_EQ(rtt_2, nqe_observer.http_rtt()); + EXPECT_EQ(rtt_2, nqe_service->GetHttpRTT()); + EXPECT_EQ(rtt_2, nqe_service->GetTransportRTT()); + EXPECT_FALSE(nqe_service->GetDownstreamThroughputKbps().has_value()); + nqe_service->RemoveRTTAndThroughputEstimatesObserver(&nqe_observer); base::TimeDelta rtt_3 = base::TimeDelta::FromMilliseconds(300); @@ -269,6 +277,10 @@ nqe_test_util::OverrideRTTsAndWait(rtt_3); EXPECT_EQ(rtt_2, nqe_observer.http_rtt()); + EXPECT_EQ(rtt_3, nqe_service->GetHttpRTT()); + EXPECT_EQ(rtt_3, nqe_service->GetTransportRTT()); + EXPECT_FALSE(nqe_service->GetDownstreamThroughputKbps().has_value()); + // Observer should be notified on addition. TestRTTAndThroughputEstimatesObserver nqe_observer_2; nqe_service->AddRTTAndThroughputEstimatesObserver(&nqe_observer_2);
diff --git a/chrome/browser/notifications/notification_platform_bridge_mac.mm b/chrome/browser/notifications/notification_platform_bridge_mac.mm index 29277e1..dfee46c 100644 --- a/chrome/browser/notifications/notification_platform_bridge_mac.mm +++ b/chrome/browser/notifications/notification_platform_bridge_mac.mm
@@ -11,6 +11,7 @@ #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" +#include "base/mac/scoped_mach_port.h" #include "base/mac/scoped_nsobject.h" #include "base/strings/nullable_string16.h" #include "base/strings/string_number_conversions.h" @@ -25,13 +26,15 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h" -#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h" #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h" +#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h" #import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac.h" #include "chrome/common/features.h" #include "chrome/grit/generated_resources.h" +#include "components/crash/content/app/crashpad.h" #include "components/url_formatter/elide_url.h" #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationConstants.h" +#include "third_party/crashpad/crashpad/client/crashpad_client.h" #include "ui/base/l10n/l10n_util_mac.h" #include "url/gurl.h" #include "url/origin.h" @@ -428,6 +431,11 @@ @implementation AlertDispatcherImpl { // The connection to the XPC server in charge of delivering alerts. base::scoped_nsobject<NSXPCConnection> xpcConnection_; + + // YES if the remote object has had |-setMachExceptionPort:| called + // since the service was last started, interrupted, or invalidated. + // If NO, then -serviceProxy will set the exception port. + BOOL setExceptionPort_; } - (instancetype)init { @@ -443,12 +451,14 @@ xpcConnection_.get().interruptionHandler = ^{ LOG(WARNING) << "connection interrupted: interruptionHandler: "; + setExceptionPort_ = NO; // TODO(miguelg): perhaps add some UMA here. // We will be getting this handler both when the XPC server crashes or // when it decides to close the connection. }; xpcConnection_.get().invalidationHandler = ^{ LOG(WARNING) << "connection invalidationHandler received"; + setExceptionPort_ = NO; // This means that the connection should be recreated if it needs // to be used again. It should not really happen. DCHECK(false) << "XPC Connection invalidated"; @@ -464,23 +474,44 @@ } - (void)dispatchNotification:(NSDictionary*)data { - [[xpcConnection_ remoteObjectProxy] deliverNotification:data]; + [[self serviceProxy] deliverNotification:data]; } - (void)closeNotificationWithId:(NSString*)notificationId withProfileId:(NSString*)profileId { - [[xpcConnection_ remoteObjectProxy] closeNotificationWithId:notificationId - withProfileId:profileId]; + [[self serviceProxy] closeNotificationWithId:notificationId + withProfileId:profileId]; } - (void)closeAllNotifications { - [[xpcConnection_ remoteObjectProxy] closeAllNotifications]; + [[self serviceProxy] closeAllNotifications]; } -// NotificationReply implementation +// NotificationReply: + - (void)notificationClick:(NSDictionary*)notificationResponseData { NotificationPlatformBridgeMac::ProcessNotificationResponse( notificationResponseData); } +// Private methods: + +// Retrieves the connection's remoteObjectProxy. Always use this as opposed +// to going directly through the connection, since this will ensure that the +// service has its exception port configured for crash reporting. +- (id<NotificationDelivery>)serviceProxy { + id<NotificationDelivery> proxy = [xpcConnection_ remoteObjectProxy]; + + if (!setExceptionPort_) { + base::mac::ScopedMachSendRight exceptionPort( + crash_reporter::GetCrashpadClient().GetHandlerMachPort()); + base::scoped_nsobject<CrXPCMachPort> xpcPort( + [[CrXPCMachPort alloc] initWithMachSendRight:std::move(exceptionPort)]); + [proxy setMachExceptionPort:xpcPort]; + setExceptionPort_ = YES; + } + + return proxy; +} + @end
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc index c17e82e..e1d11c4 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -104,6 +104,22 @@ RegisterInputEventObserver(new_host); } +void MetricsWebContentsObserver::MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + const content::WebContentsObserver::MediaPlayerId& id) { + content::RenderFrameHost* render_frame_host = id.first; + if (!render_frame_host->GetRenderViewHost() || + render_frame_host->GetRenderViewHost()->GetMainFrame() != + web_contents()->GetMainFrame()) { + // Ignore media that starts playing in a document that was navigated away + // from. + return; + } + if (committed_load_) + committed_load_->MediaStartedPlaying( + video_type, render_frame_host == web_contents()->GetMainFrame()); +} + bool MetricsWebContentsObserver::OnMessageReceived( const IPC::Message& message, content::RenderFrameHost* render_frame_host) {
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h index 681e7ce..a725db2 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
@@ -65,6 +65,9 @@ void RenderProcessGone(base::TerminationStatus status) override; void RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) override; + void MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + const content::WebContentsObserver::MediaPlayerId& id) override; // These methods are forwarded from the MetricsNavigationThrottle. void WillStartNavigationRequest(content::NavigationHandle* navigation_handle);
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc new file mode 100644 index 0000000..6e73c491 --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc
@@ -0,0 +1,71 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h" + +#include "chrome/browser/page_load_metrics/page_load_metrics_util.h" +#include "chrome/common/page_load_metrics/page_load_timing.h" + +namespace { + +const char kHistogramNetworkBytes[] = + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Network"; +const char kHistogramCacheBytes[] = + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Cache"; +const char kHistogramTotalBytes[] = + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Total"; + +} // namespace + +MediaPageLoadMetricsObserver::MediaPageLoadMetricsObserver() + : cache_bytes_(0), network_bytes_(0), played_media_(false) {} + +MediaPageLoadMetricsObserver::~MediaPageLoadMetricsObserver() = default; + +void MediaPageLoadMetricsObserver::OnLoadedResource( + const page_load_metrics::ExtraRequestInfo& extra_request_info) { + if (extra_request_info.was_cached) { + cache_bytes_ += extra_request_info.raw_body_bytes; + } else { + network_bytes_ += extra_request_info.raw_body_bytes; + } +} + +page_load_metrics::PageLoadMetricsObserver::ObservePolicy +MediaPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the + // app is about to be backgrounded, as part of the Activity.onPause() + // flow. After this method is invoked, Chrome may be killed without further + // notification, so we record final metrics collected up to this point. + if (info.did_commit && played_media_) { + RecordByteHistograms(); + } + return STOP_OBSERVING; +} + +void MediaPageLoadMetricsObserver::OnComplete( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + if (!played_media_) + return; + RecordByteHistograms(); +} + +void MediaPageLoadMetricsObserver::MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + bool is_in_main_frame) { + if (played_media_) + return; + // Track media (audio or video) in all frames of the page load. + played_media_ = true; +} + +void MediaPageLoadMetricsObserver::RecordByteHistograms() { + DCHECK(played_media_); + PAGE_BYTES_HISTOGRAM(kHistogramNetworkBytes, network_bytes_); + PAGE_BYTES_HISTOGRAM(kHistogramCacheBytes, cache_bytes_); + PAGE_BYTES_HISTOGRAM(kHistogramTotalBytes, network_bytes_ + cache_bytes_); +}
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h new file mode 100644 index 0000000..bc3c684 --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h
@@ -0,0 +1,55 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_MEDIA_PAGE_LOAD_METRICS_OBSERVER_H_ +#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_MEDIA_PAGE_LOAD_METRICS_OBSERVER_H_ + +#include <stdint.h> + +#include "base/macros.h" +#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" +#include "content/public/browser/web_contents_observer.h" + +namespace page_load_metrics { +struct PageLoadExtraInfo; +struct PageLoadTiming; +} + +// Observer responsible for recording metrics on pages that play at least one +// MEDIA request. +class MediaPageLoadMetricsObserver + : public page_load_metrics::PageLoadMetricsObserver { + public: + MediaPageLoadMetricsObserver(); + ~MediaPageLoadMetricsObserver() override; + + // page_load_metrics::PageLoadMetricsObserver: + void OnComplete(const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) override; + page_load_metrics::PageLoadMetricsObserver::ObservePolicy + FlushMetricsOnAppEnterBackground( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) override; + void OnLoadedResource( + const page_load_metrics::ExtraRequestInfo& extra_request_info) override; + void MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + bool is_in_main_frame) override; + + private: + // Records histograms for byte information. + void RecordByteHistograms(); + + // The number of body (not header) prefilter bytes consumed by requests for + // the page. + int64_t cache_bytes_; + int64_t network_bytes_; + + // Whether the page load played a media element. + bool played_media_; + + DISALLOW_COPY_AND_ASSIGN(MediaPageLoadMetricsObserver); +}; + +#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_MEDIA_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc new file mode 100644 index 0000000..d8e9e8c --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,150 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h" + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/test/histogram_tester.h" +#include "base/time/time.h" +#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h" +#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" +#include "chrome/common/page_load_metrics/page_load_timing.h" +#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h" +#include "url/gurl.h" + +namespace { + +const char kDefaultTestUrl[] = "https://google.com"; + +} // namespace + +class MediaPageLoadMetricsObserverTest + : public page_load_metrics::PageLoadMetricsObserverTestHarness { + public: + MediaPageLoadMetricsObserverTest() {} + ~MediaPageLoadMetricsObserverTest() override = default; + + void ResetTest() { + // Reset to the default testing state. Does not reset histogram state. + timing_.navigation_start = base::Time::FromDoubleT(1); + timing_.response_start = base::TimeDelta::FromSeconds(2); + timing_.parse_start = base::TimeDelta::FromSeconds(3); + timing_.first_contentful_paint = base::TimeDelta::FromSeconds(4); + timing_.first_image_paint = base::TimeDelta::FromSeconds(5); + timing_.first_text_paint = base::TimeDelta::FromSeconds(6); + timing_.load_event_start = base::TimeDelta::FromSeconds(7); + PopulateRequiredTimingFields(&timing_); + + network_bytes_ = 0; + cache_bytes_ = 0; + } + + void SimulatePageLoad(bool simulate_play_media, + bool simulate_app_background) { + NavigateAndCommit(GURL(kDefaultTestUrl)); + + if (simulate_play_media) + SimulateMediaPlayed(); + + SimulateTimingUpdate(timing_); + + // Prepare 4 resources of varying size and configurations. + page_load_metrics::ExtraRequestInfo resources[] = { + // Cached request. + {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */, + false /* data_reduction_proxy_used*/, + 0 /* original_network_content_length */}, + // Uncached non-proxied request. + {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, + false /* data_reduction_proxy_used*/, + 1024 * 40 /* original_network_content_length */}, + // Uncached proxied request with .1 compression ratio. + {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, + false /* data_reduction_proxy_used*/, + 1024 * 40 /* original_network_content_length */}, + // Uncached proxied request with .5 compression ratio. + {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, + false /* data_reduction_proxy_used*/, + 1024 * 40 /* original_network_content_length */}, + }; + + for (auto request : resources) { + SimulateLoadedResource(request); + if (!request.was_cached) { + network_bytes_ += request.raw_body_bytes; + } else { + cache_bytes_ += request.raw_body_bytes; + } + } + + if (simulate_app_background) { + // The histograms should be logged when the app is backgrounded. + SimulateAppEnterBackground(); + } else { + NavigateToUntrackedUrl(); + } + } + + protected: + void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override { + tracker->AddObserver(base::MakeUnique<MediaPageLoadMetricsObserver>()); + } + + // Simulated byte usage since the last time the test was reset. + int64_t network_bytes_; + int64_t cache_bytes_; + + private: + page_load_metrics::PageLoadTiming timing_; + + DISALLOW_COPY_AND_ASSIGN(MediaPageLoadMetricsObserverTest); +}; + +TEST_F(MediaPageLoadMetricsObserverTest, MediaPlayed) { + ResetTest(); + SimulatePageLoad(true /* simulate_play_media */, + false /* simulate_app_background */); + + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Network", + static_cast<int>(network_bytes_ / 1024), 1); + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Cache", + static_cast<int>(cache_bytes_ / 1024), 1); + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Total", + static_cast<int>((network_bytes_ + cache_bytes_) / 1024), 1); +} + +TEST_F(MediaPageLoadMetricsObserverTest, MediaPlayedAppBackground) { + ResetTest(); + SimulatePageLoad(true /* simulate_play_media */, + true /* simulate_app_background */); + + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Network", + static_cast<int>(network_bytes_ / 1024), 1); + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Cache", + static_cast<int>(cache_bytes_ / 1024), 1); + histogram_tester().ExpectUniqueSample( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Total", + static_cast<int>((network_bytes_ + cache_bytes_) / 1024), 1); +} + +TEST_F(MediaPageLoadMetricsObserverTest, MediaNotPlayed) { + ResetTest(); + SimulatePageLoad(false /* simulate_play_media */, + false /* simulate_app_background */); + + histogram_tester().ExpectTotalCount( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Network", 0); + histogram_tester().ExpectTotalCount( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Cache", 0); + histogram_tester().ExpectTotalCount( + "PageLoad.Clients.MediaPageLoad.Experimental.Bytes.Total", 0); +}
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc index 3de5193..c74e1b8 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -14,6 +14,7 @@ #include "chrome/common/page_load_metrics/page_load_metrics_messages.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/test/web_contents_tester.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" @@ -152,6 +153,14 @@ observer_->FlushMetricsOnAppEnterBackground(); } +void PageLoadMetricsObserverTestHarness::SimulateMediaPlayed() { + content::WebContentsObserver::MediaPlayerInfo video_type( + true /* in_has_video*/); + content::RenderFrameHost* render_frame_host = web_contents()->GetMainFrame(); + observer_->MediaStartedPlaying(video_type, + std::make_pair(render_frame_host, 0)); +} + const base::HistogramTester& PageLoadMetricsObserverTestHarness::histogram_tester() const { return histogram_tester_;
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h index 67d244e..2f6fd42 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -65,6 +65,9 @@ // Simulates the app being backgrounded. void SimulateAppEnterBackground(); + // Simulate playing a media element. + void SimulateMediaPlayed(); + const base::HistogramTester& histogram_tester() const; // Gets the PageLoadExtraInfo for the committed_load_ in observer_.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc index ffca700..21940835 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h" #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h" +#include "chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/prerender_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h" @@ -79,8 +80,9 @@ base::MakeUnique<google_captcha_observer::GoogleCaptchaObserver>()); tracker->AddObserver( base::MakeUnique<DocumentWritePageLoadMetricsObserver>()); + tracker->AddObserver(base::MakeUnique<MediaPageLoadMetricsObserver>()); tracker->AddObserver( - base::WrapUnique(new previews::PreviewsPageLoadMetricsObserver())); + base::MakeUnique<previews::PreviewsPageLoadMetricsObserver>()); tracker->AddObserver( base::MakeUnique<ServiceWorkerPageLoadMetricsObserver>()); tracker->AddObserver(base::MakeUnique<SubresourceFilterMetricsObserver>());
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h index 80600db..41acd9c 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -11,6 +11,7 @@ #include "base/optional.h" #include "chrome/common/page_load_metrics/page_load_timing.h" #include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents_observer.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" #include "url/gurl.h" @@ -323,6 +324,11 @@ virtual void OnLoadingBehaviorObserved( const page_load_metrics::PageLoadExtraInfo& extra_info) {} + // Invoked when a media element starts playing. + virtual void MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + bool is_in_main_frame) {} + // Invoked when the UMA metrics subsystem is persisting metrics as the // application goes into the background, on platforms where the browser // process may be killed after backgrounding (Android). Implementers should
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc index aff76c3..dfccbaf 100644 --- a/chrome/browser/page_load_metrics/page_load_tracker.cc +++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -19,6 +19,7 @@ #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/common/browser_side_navigation_policy.h" #include "ui/base/page_transition_types.h" @@ -732,4 +733,11 @@ } } +void PageLoadTracker::MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + bool is_in_main_frame) { + for (const auto& observer : observers_) + observer->MediaStartedPlaying(video_type, is_in_main_frame); +} + } // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h index bbd86413..08111a55 100644 --- a/chrome/browser/page_load_metrics/page_load_tracker.h +++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -15,6 +15,7 @@ #include "chrome/browser/page_load_metrics/user_input_tracker.h" #include "chrome/common/page_load_metrics/page_load_timing.h" #include "content/public/browser/global_request_id.h" +#include "content/public/browser/web_contents_observer.h" #include "ui/base/page_transition_types.h" class GURL; @@ -231,6 +232,11 @@ bool HasMatchingNavigationRequestID( const content::GlobalRequestID& request_id) const; + // Invoked when a media element starts playing. + void MediaStartedPlaying( + const content::WebContentsObserver::MediaPlayerInfo& video_type, + bool is_in_main_frame); + private: // This function converts a TimeTicks value taken in the browser process // to navigation_start_ if:
diff --git a/chrome/browser/permissions/delegation_tracker.cc b/chrome/browser/permissions/delegation_tracker.cc deleted file mode 100644 index 9b1183d..0000000 --- a/chrome/browser/permissions/delegation_tracker.cc +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/permissions/delegation_tracker.h" - -#include <unordered_set> - -#include "base/memory/ptr_util.h" -#include "chrome/browser/permissions/permission_util.h" -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" - -class DelegationTracker::DelegatedForChild : content::WebContentsObserver { - public: - DelegatedForChild(content::RenderFrameHost* child_rfh, - const std::vector<ContentSettingsType>& permissions, - const base::Callback<void(content::RenderFrameHost*)>& - rfh_destroyed_callback) - : content::WebContentsObserver( - content::WebContents::FromRenderFrameHost(child_rfh)), - child_rfh_(child_rfh), - permissions_(permissions.begin(), permissions.end()), - rfh_destroyed_callback_(rfh_destroyed_callback) {} - - ~DelegatedForChild() override {} - - bool HasPermission(ContentSettingsType permission) { - return permissions_.count(permission) == 1; - } - - private: - DISALLOW_COPY_AND_ASSIGN(DelegatedForChild); - - void ClearPermissions(content::RenderFrameHost* render_frame_host) { - if (render_frame_host == child_rfh_) - rfh_destroyed_callback_.Run(render_frame_host); // Will delete |this|. - } - - // WebContentsObserver - void RenderFrameHostChanged(content::RenderFrameHost* old_host, - content::RenderFrameHost* new_host) override { - ClearPermissions(old_host); - } - - void FrameDeleted(content::RenderFrameHost* render_frame_host) override { - ClearPermissions(render_frame_host); - } - - void DidFinishNavigation( - content::NavigationHandle* navigation_handle) override { - if (navigation_handle->HasCommitted()) - ClearPermissions(navigation_handle->GetRenderFrameHost()); - } - - content::RenderFrameHost* child_rfh_; - - std::unordered_set<ContentSettingsType, ContentSettingsTypeHash> permissions_; - - base::Callback<void(content::RenderFrameHost*)> rfh_destroyed_callback_; -}; - -DelegationTracker::DelegationTracker() {} - -DelegationTracker::~DelegationTracker() {} - -void DelegationTracker::SetDelegatedPermissions( - content::RenderFrameHost* child_rfh, - const std::vector<ContentSettingsType>& permissions) { - DCHECK(child_rfh && child_rfh->GetParent()); - delegated_permissions_[child_rfh] = base::MakeUnique<DelegatedForChild>( - child_rfh, permissions, - base::Bind(&DelegationTracker::RenderFrameHostChanged, - base::Unretained(this))); -} - -bool DelegationTracker::IsGranted(content::RenderFrameHost* requesting_rfh, - ContentSettingsType permission) { - content::RenderFrameHost* child_rfh = requesting_rfh; - while (child_rfh->GetParent()) { - // Parents with unique origins can't delegate permission. - url::Origin parent_origin = - child_rfh->GetParent()->GetLastCommittedOrigin(); - if (parent_origin.unique()) - return false; - - if (!child_rfh->GetLastCommittedOrigin().IsSameOriginWith(parent_origin)) { - const auto& it = delegated_permissions_.find(child_rfh); - if (it == delegated_permissions_.end()) - return false; - if (!it->second->HasPermission(permission)) - return false; - } - child_rfh = child_rfh->GetParent(); - } - return true; -} - -void DelegationTracker::RenderFrameHostChanged(content::RenderFrameHost* rfh) { - delegated_permissions_.erase(rfh); -}
diff --git a/chrome/browser/permissions/delegation_tracker.h b/chrome/browser/permissions/delegation_tracker.h deleted file mode 100644 index 68c1e79..0000000 --- a/chrome/browser/permissions/delegation_tracker.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PERMISSIONS_DELEGATION_TRACKER_H_ -#define CHROME_BROWSER_PERMISSIONS_DELEGATION_TRACKER_H_ - -#include <memory> -#include <unordered_map> -#include <vector> - -#include "base/macros.h" -#include "components/content_settings/core/common/content_settings_types.h" - -namespace content { - -class RenderFrameHost; - -} // namespace content - -// Keeps track of which permissions are delegated to frames. There are two -// operations possible: -// 1) Setting the permissions which are delegated to a frame by its parent, and -// 2) Querying whether a particular permission is granted to a frame. -// -// If a frame is destroyed or navigated, permissions will no longer be delegated -// to it. -class DelegationTracker { - public: - DelegationTracker(); - ~DelegationTracker(); - - // Set the |permissions| which are delegated to |child_rfh| by its parent. - void SetDelegatedPermissions( - content::RenderFrameHost* child_rfh, - const std::vector<ContentSettingsType>& permissions); - - // Query whether |permission| is granted to |requesting_rfh|. This will return - // true if |requesting_rfh| is a top-level frame or if it has been delegated - // |permission| through its ancestor frames. Specifically, each frame on the - // path between the main frame and |requesting_rfh| must either delegate - // |permission| to it's child OR have the same origin as it's child on that - // path in order for this to return true. - bool IsGranted(content::RenderFrameHost* requesting_rfh, - ContentSettingsType permission); - - private: - class DelegatedForChild; - - void RenderFrameHostChanged(content::RenderFrameHost* rfh); - - std::unordered_map<content::RenderFrameHost*, - std::unique_ptr<DelegatedForChild>> - delegated_permissions_; - - DISALLOW_COPY_AND_ASSIGN(DelegationTracker); -}; - -#endif // CHROME_BROWSER_PERMISSIONS_DELEGATION_TRACKER_H_
diff --git a/chrome/browser/permissions/delegation_tracker_unittest.cc b/chrome/browser/permissions/delegation_tracker_unittest.cc deleted file mode 100644 index f00bb14..0000000 --- a/chrome/browser/permissions/delegation_tracker_unittest.cc +++ /dev/null
@@ -1,227 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/permissions/delegation_tracker.h" - -#include "chrome/test/base/chrome_render_view_host_test_harness.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/test/test_renderer_host.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -const char* kOrigin1 = "https://google.com"; -const char* kOrigin2 = "https://maps.google.com"; -const char* kOrigin3 = "https://example.com"; -const char* kUniqueOrigin = "about:blank"; - -class DelegationTrackerTest : public ChromeRenderViewHostTestHarness { - protected: - content::RenderFrameHost* GetMainRFH(const char* origin) { - content::RenderFrameHost* result = web_contents()->GetMainFrame(); - content::RenderFrameHostTester::For(result) - ->InitializeRenderFrameIfNeeded(); - content::RenderFrameHostTester::For(result)->SimulateNavigationCommit( - GURL(origin)); - return result; - } - - content::RenderFrameHost* AddChildRFH(content::RenderFrameHost* parent, - const char* origin) { - content::RenderFrameHost* result = - content::RenderFrameHostTester::For(parent)->AppendChild(""); - content::RenderFrameHostTester::For(result) - ->InitializeRenderFrameIfNeeded(); - content::RenderFrameHostTester::For(result)->SimulateNavigationCommit( - GURL(origin)); - return result; - } -}; - -TEST_F(DelegationTrackerTest, SingleFrame) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, SingleAncestorSameOrigin) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin1); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, SingleAncestorNoDelegation) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, SingleAncestorPermissionDelegated) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2); - - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); -} - -TEST_F(DelegationTrackerTest, SingleAncestorMultiplePermissionsDelegated) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2); - - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION, - CONTENT_SETTINGS_TYPE_NOTIFICATIONS}); - - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); -} - -TEST_F(DelegationTrackerTest, SingleAncestorMultipleChildren) { - DelegationTracker tracker; - content::RenderFrameHost* parent = GetMainRFH(kOrigin1); - content::RenderFrameHost* child1 = AddChildRFH(parent, kOrigin2); - content::RenderFrameHost* child2 = AddChildRFH(parent, kOrigin2); - - tracker.SetDelegatedPermissions(child1, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE(tracker.IsGranted(child1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, MultipleAncestorsNotDelegated) { - DelegationTracker tracker; - content::RenderFrameHost* grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* parent = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* child1 = AddChildRFH(parent, kOrigin3); - content::RenderFrameHost* child2 = AddChildRFH(parent, kOrigin3); - - tracker.SetDelegatedPermissions(child1, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_FALSE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, MultipleAncestorsDelegated) { - DelegationTracker tracker; - content::RenderFrameHost* grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* parent = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* child1 = AddChildRFH(parent, kOrigin3); - content::RenderFrameHost* child2 = AddChildRFH(parent, kOrigin3); - - tracker.SetDelegatedPermissions(parent, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - tracker.SetDelegatedPermissions(child1, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, MultipleAncestorsSameOrigin) { - DelegationTracker tracker; - content::RenderFrameHost* grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* parent = AddChildRFH(grandparent, kOrigin1); - content::RenderFrameHost* child1 = AddChildRFH(parent, kOrigin1); - content::RenderFrameHost* child2 = AddChildRFH(parent, kOrigin1); - - tracker.SetDelegatedPermissions(parent, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - tracker.SetDelegatedPermissions(child1, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, MultipleAncestorsComplexSinglePermission) { - DelegationTracker tracker; - content::RenderFrameHost* great_grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* grandparent = - AddChildRFH(great_grandparent, kOrigin2); - content::RenderFrameHost* parent1 = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* parent2 = AddChildRFH(grandparent, kOrigin3); - content::RenderFrameHost* child = AddChildRFH(parent1, kOrigin3); - - tracker.SetDelegatedPermissions(grandparent, - {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE( - tracker.IsGranted(grandparent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(parent1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(parent2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, MultipleAncestorsComplexMultiplePermissions) { - DelegationTracker tracker; - content::RenderFrameHost* great_grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* grandparent = - AddChildRFH(great_grandparent, kOrigin2); - content::RenderFrameHost* parent1 = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* parent2 = AddChildRFH(grandparent, kOrigin3); - content::RenderFrameHost* child = AddChildRFH(parent1, kOrigin3); - - tracker.SetDelegatedPermissions( - grandparent, - {CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTINGS_TYPE_NOTIFICATIONS}); - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE( - tracker.IsGranted(grandparent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE( - tracker.IsGranted(grandparent, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); - - EXPECT_TRUE(tracker.IsGranted(parent1, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(parent1, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); - - EXPECT_FALSE(tracker.IsGranted(parent2, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(parent2, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); - - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); -} - -TEST_F(DelegationTrackerTest, RenderFrameHostChanged) { - DelegationTracker tracker; - content::RenderFrameHost* grandparent = GetMainRFH(kOrigin1); - content::RenderFrameHost* parent = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin3); - - tracker.SetDelegatedPermissions(parent, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - EXPECT_TRUE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_TRUE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - - content::RenderFrameHostTester::For(parent)->SimulateNavigationCommit( - GURL(kUniqueOrigin)); - - EXPECT_FALSE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -} - -TEST_F(DelegationTrackerTest, UniqueOrigins) { - DelegationTracker tracker; - content::RenderFrameHost* grandparent = GetMainRFH(kUniqueOrigin); - content::RenderFrameHost* parent = AddChildRFH(grandparent, kOrigin2); - content::RenderFrameHost* child = AddChildRFH(parent, kOrigin3); - - tracker.SetDelegatedPermissions(parent, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - tracker.SetDelegatedPermissions(child, {CONTENT_SETTINGS_TYPE_GEOLOCATION}); - - // Unique origins should never be able to delegate permission. - EXPECT_FALSE(tracker.IsGranted(parent, CONTENT_SETTINGS_TYPE_GEOLOCATION)); - EXPECT_FALSE(tracker.IsGranted(child, CONTENT_SETTINGS_TYPE_GEOLOCATION)); -}
diff --git a/chrome/browser/permissions/permission_prompt_android.h b/chrome/browser/permissions/permission_prompt_android.h index e115345..9c052e2 100644 --- a/chrome/browser/permissions/permission_prompt_android.h +++ b/chrome/browser/permissions/permission_prompt_android.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_PERMISSIONS_PERMISSION_PROMPT_ANDROID_H_ #define CHROME_BROWSER_PERMISSIONS_PERMISSION_PROMPT_ANDROID_H_ -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" class InfoBarService;
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc index eab05c2..1ed9063 100644 --- a/chrome/browser/permissions/permission_request_manager.cc +++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -12,7 +12,7 @@ #include "build/build_config.h" #include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_uma_util.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/permissions/permission_request_manager.h b/chrome/browser/permissions/permission_request_manager.h index f6c4c4a..b2df0b9 100644 --- a/chrome/browser/permissions/permission_request_manager.h +++ b/chrome/browser/permissions/permission_request_manager.h
@@ -11,7 +11,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h"
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc index 4e74b17..e018fa6 100644 --- a/chrome/browser/permissions/permission_request_manager_browsertest.cc +++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -7,11 +7,18 @@ #include "base/command_line.h" #include "base/metrics/field_trial.h" #include "build/build_config.h" +#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" +#include "chrome/browser/custom_handlers/register_protocol_handler_permission_request.h" +#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" +#include "chrome/browser/media/webrtc/media_stream_devices_controller.h" #include "chrome/browser/permissions/permission_context_base.h" +#include "chrome/browser/permissions/permission_request_impl.h" #include "chrome/browser/permissions/permission_util.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/common/content_settings_types.h" @@ -20,6 +27,39 @@ #include "content/public/test/test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" +namespace test { +class MediaStreamDevicesControllerTestApi + : public MediaStreamDevicesController::PermissionPromptDelegate { + public: + static void AddRequestToManager( + PermissionRequestManager* manager, + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + MediaStreamDevicesControllerTestApi delegate(manager); + MediaStreamDevicesController::RequestPermissionsWithDelegate( + web_contents, request, callback, &delegate); + } + + private: + // MediaStreamDevicesController::PermissionPromptDelegate: + void ShowPrompt( + bool user_gesture, + content::WebContents* web_contents, + std::unique_ptr<MediaStreamDevicesController> controller) override { + manager_->AddRequest(controller.release()); + } + + explicit MediaStreamDevicesControllerTestApi( + PermissionRequestManager* manager) + : manager_(manager) {} + + PermissionRequestManager* manager_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesControllerTestApi); +}; +} // namespace test + namespace { const char* kPermissionsKillSwitchFieldStudy = @@ -68,8 +108,166 @@ private: std::unique_ptr<MockPermissionPromptFactory> mock_permission_prompt_factory_; + + DISALLOW_COPY_AND_ASSIGN(PermissionRequestManagerBrowserTest); }; +// Harness for testing permissions dialogs invoked by PermissionRequestManager. +// Uses a "real" PermissionPromptFactory rather than a mock. +class PermissionDialogTest + : public SupportsTestDialog<PermissionRequestManagerBrowserTest> { + public: + PermissionDialogTest() {} + + // InProcessBrowserTest: + void SetUpOnMainThread() override { + // Skip super: It will install a mock permission UI factory, but for this + // test we want to show "real" UI. + InProcessBrowserTest::SetUpOnMainThread(); + } + + private: + GURL GetUrl() { return GURL("https://example.com"); } + + PermissionRequest* MakeRegisterProtocolHandlerRequest(); + void AddMediaRequest(PermissionRequestManager* manager, + ContentSettingsType permission); + PermissionRequest* MakePermissionRequest(ContentSettingsType permission); + + // TestBrowserDialog: + void ShowDialog(const std::string& name) override; + + // Holds requests that do not delete themselves. + std::vector<std::unique_ptr<PermissionRequest>> owned_requests_; + + DISALLOW_COPY_AND_ASSIGN(PermissionDialogTest); +}; + +PermissionRequest* PermissionDialogTest::MakeRegisterProtocolHandlerRequest() { + std::string protocol = "mailto"; + bool user_gesture = true; + ProtocolHandler handler = + ProtocolHandler::CreateProtocolHandler(protocol, GetUrl()); + ProtocolHandlerRegistry* registry = + ProtocolHandlerRegistryFactory::GetForBrowserContext( + browser()->profile()); + // Deleted in RegisterProtocolHandlerPermissionRequest::RequestFinished(). + return new RegisterProtocolHandlerPermissionRequest(registry, handler, + GetUrl(), user_gesture); +} + +void PermissionDialogTest::AddMediaRequest(PermissionRequestManager* manager, + ContentSettingsType permission) { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::MediaStreamRequestType request_type = content::MEDIA_DEVICE_ACCESS; + content::MediaStreamType audio_type = content::MEDIA_NO_SERVICE; + content::MediaStreamType video_type = content::MEDIA_NO_SERVICE; + std::string audio_id = "audio_id"; + std::string video_id = "video_id"; + + if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) + audio_type = content::MEDIA_DEVICE_AUDIO_CAPTURE; + else + video_type = content::MEDIA_DEVICE_VIDEO_CAPTURE; + content::MediaStreamRequest request(0, 0, 0, GetUrl(), false, request_type, + audio_id, video_id, audio_type, + video_type, false); + + // Add fake devices, otherwise the request will auto-block. + MediaCaptureDevicesDispatcher::GetInstance()->SetTestAudioCaptureDevices( + content::MediaStreamDevices( + 1, content::MediaStreamDevice(content::MEDIA_DEVICE_AUDIO_CAPTURE, + audio_id, "Fake Audio"))); + MediaCaptureDevicesDispatcher::GetInstance()->SetTestVideoCaptureDevices( + content::MediaStreamDevices( + 1, content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE, + video_id, "Fake Video"))); + + auto response = [](const content::MediaStreamDevices& devices, + content::MediaStreamRequestResult result, + std::unique_ptr<content::MediaStreamUI> ui) {}; + test::MediaStreamDevicesControllerTestApi::AddRequestToManager( + manager, web_contents, request, base::Bind(response)); +} + +PermissionRequest* PermissionDialogTest::MakePermissionRequest( + ContentSettingsType permission) { + bool user_gesture = true; + auto decided = [](bool, ContentSetting) {}; + auto cleanup = [] {}; // Leave cleanup to test harness destructor. + owned_requests_.push_back(base::MakeUnique<PermissionRequestImpl>( + GetUrl(), permission, browser()->profile(), user_gesture, + base::Bind(decided), base::Bind(cleanup))); + return owned_requests_.back().get(); +} + +void PermissionDialogTest::ShowDialog(const std::string& name) { + constexpr const char* kMultipleName = "multiple"; + // Permissions to request for a "multiple" request. Only types handled in + // PermissionRequestImpl::GetMessageTextFragment() are valid. + constexpr ContentSettingsType kMultipleRequests[] = { + CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + CONTENT_SETTINGS_TYPE_MIDI_SYSEX}; + constexpr struct { + const char* name; + ContentSettingsType type; + } kNameToType[] = { + {"flash", CONTENT_SETTINGS_TYPE_PLUGINS}, + {"geolocation", CONTENT_SETTINGS_TYPE_GEOLOCATION}, + {"protected_media", CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER}, + {"notifications", CONTENT_SETTINGS_TYPE_NOTIFICATIONS}, + {"mic", CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC}, + {"camera", CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA}, + {"protocol_handlers", CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS}, + {"midi", CONTENT_SETTINGS_TYPE_MIDI_SYSEX}, + {kMultipleName, CONTENT_SETTINGS_TYPE_DEFAULT}}; + const auto* it = std::begin(kNameToType); + for (; it != std::end(kNameToType); ++it) { + if (name == it->name) + break; + } + if (it == std::end(kNameToType)) { + ADD_FAILURE() << "Unknown: " << name; + return; + } + PermissionRequestManager* manager = GetPermissionRequestManager(); + switch (it->type) { + case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS: + manager->AddRequest(MakeRegisterProtocolHandlerRequest()); + break; + case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: + // TODO(tapted): Prompt for downloading multiple files. + break; + case CONTENT_SETTINGS_TYPE_DURABLE_STORAGE: + // TODO(tapted): Prompt for quota request. + break; + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: + AddMediaRequest(manager, it->type); + break; + // Regular permissions requests. + case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: + case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING: // Same as notifications. + case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: + case CONTENT_SETTINGS_TYPE_GEOLOCATION: + case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER: // ChromeOS only. + case CONTENT_SETTINGS_TYPE_PPAPI_BROKER: + case CONTENT_SETTINGS_TYPE_PLUGINS: // Flash. + manager->AddRequest(MakePermissionRequest(it->type)); + break; + case CONTENT_SETTINGS_TYPE_DEFAULT: + EXPECT_EQ(kMultipleName, name); + for (auto request : kMultipleRequests) + manager->AddRequest(MakePermissionRequest(request)); + break; + default: + ADD_FAILURE() << "Not a permission type, or one that doesn't prompt."; + return; + } + manager->DisplayPendingRequests(); +} + // Requests before the load event should be bundled into one bubble. // http://crbug.com/512849 flaky IN_PROC_BROWSER_TEST_F(PermissionRequestManagerBrowserTest, @@ -248,4 +446,55 @@ EXPECT_EQ(1, bubble_factory()->total_request_count()); } +// Host wants to run flash. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_flash) { + RunDialog(); +} + +// Host wants to know your location. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_geolocation) { + RunDialog(); +} + +// Host wants to show notifications. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_notifications) { + RunDialog(); +} + +// Host wants to use your microphone. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_mic) { + RunDialog(); +} + +// Host wants to use your camera. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_camera) { + RunDialog(); +} + +// Host wants to open email links. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_protocol_handlers) { + RunDialog(); +} + +// Host wants to use your MIDI devices. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_midi) { + RunDialog(); +} + +// Shows a permissions bubble with multiple requests. +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_multiple) { + RunDialog(); +} + +// CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER is ChromeOS only. +#if defined(OS_CHROMEOS) +#define MAYBE_InvokeDialog_protected_media InvokeDialog_protected_media +#else +#define MAYBE_InvokeDialog_protected_media DISABLED_InvokeDialog_protected_media +#endif +IN_PROC_BROWSER_TEST_F(PermissionDialogTest, + MAYBE_InvokeDialog_protected_media) { + RunDialog(); +} + } // anonymous namespace
diff --git a/chrome/browser/permissions/permission_request_manager_unittest.cc b/chrome/browser/permissions/permission_request_manager_unittest.cc index 14cfdbc1..a9d6cc1 100644 --- a/chrome/browser/permissions/permission_request_manager_unittest.cc +++ b/chrome/browser/permissions/permission_request_manager_unittest.cc
@@ -13,7 +13,7 @@ #include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_uma_util.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/permissions/permissions_browsertest.cc b/chrome/browser/permissions/permissions_browsertest.cc index a95a94f..4adc2125 100644 --- a/chrome/browser/permissions/permissions_browsertest.cc +++ b/chrome/browser/permissions/permissions_browsertest.cc
@@ -7,8 +7,8 @@ #include "base/command_line.h" #include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/plugins/flash_permission_browsertest.cc b/chrome/browser/plugins/flash_permission_browsertest.cc index 19b287ba..227bfc0 100644 --- a/chrome/browser/plugins/flash_permission_browsertest.cc +++ b/chrome/browser/plugins/flash_permission_browsertest.cc
@@ -8,7 +8,7 @@ #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/permissions/permissions_browsertest.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/ui_test_utils.h" #include "components/variations/variations_switches.h"
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc index af3de65..dea2c3a 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.cc +++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -81,6 +81,10 @@ using content::BrowserContext; using content::BrowserThread; +using EnforcementLevel = PrefHashFilter::EnforcementLevel; +using PrefTrackingStrategy = PrefHashFilter::PrefTrackingStrategy; +using ValueType = PrefHashFilter::ValueType; + namespace { #if defined(OS_WIN) @@ -97,158 +101,80 @@ // See CleanupDeprecatedTrackedPreferences() in pref_hash_filter.cc to remove a // deprecated tracked preference. const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = { - { - 0, prefs::kShowHomeButton, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 1, prefs::kHomePageIsNewTabPage, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 2, prefs::kHomePage, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 3, prefs::kRestoreOnStartup, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 4, prefs::kURLsToRestoreOnStartup, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {0, prefs::kShowHomeButton, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {1, prefs::kHomePageIsNewTabPage, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {2, prefs::kHomePage, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {3, prefs::kRestoreOnStartup, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {4, prefs::kURLsToRestoreOnStartup, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #if BUILDFLAG(ENABLE_EXTENSIONS) - { - 5, extensions::pref_names::kExtensions, - PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::TRACKING_STRATEGY_SPLIT, - PrefHashFilter::VALUE_IMPERSONAL - }, + {5, extensions::pref_names::kExtensions, EnforcementLevel::NO_ENFORCEMENT, + PrefTrackingStrategy::SPLIT, ValueType::IMPERSONAL}, #endif - { - 6, prefs::kGoogleServicesLastUsername, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_PERSONAL - }, - { - 7, prefs::kSearchProviderOverrides, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {6, prefs::kGoogleServicesLastUsername, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL}, + {7, prefs::kSearchProviderOverrides, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #if !defined(OS_ANDROID) - { - 11, prefs::kPinnedTabs, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {11, prefs::kPinnedTabs, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #endif - { - 14, DefaultSearchManager::kDefaultSearchProviderDataPrefName, - PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - // Protecting kPreferenceResetTime does two things: - // 1) It ensures this isn't accidently set by someone stomping the pref - // file. - // 2) More importantly, it declares kPreferenceResetTime as a protected - // pref which is required for it to be visible when queried via the - // SegregatedPrefStore. This is because it's written directly in the - // protected JsonPrefStore by that store's PrefHashFilter if there was - // a reset in FilterOnLoad and SegregatedPrefStore will not look for it - // in the protected JsonPrefStore unless it's declared as a protected - // preference here. - 15, user_prefs::kPreferenceResetTime, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - // kSyncRemainingRollbackTries is deprecated and will be removed a few - // releases after M50. - { - 18, prefs::kSafeBrowsingIncidentsSent, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {14, DefaultSearchManager::kDefaultSearchProviderDataPrefName, + EnforcementLevel::NO_ENFORCEMENT, PrefTrackingStrategy::ATOMIC, + ValueType::IMPERSONAL}, + {// Protecting kPreferenceResetTime does two things: + // 1) It ensures this isn't accidently set by someone stomping the pref + // file. + // 2) More importantly, it declares kPreferenceResetTime as a protected + // pref which is required for it to be visible when queried via the + // SegregatedPrefStore. This is because it's written directly in the + // protected JsonPrefStore by that store's PrefHashFilter if there was + // a reset in FilterOnLoad and SegregatedPrefStore will not look for it + // in the protected JsonPrefStore unless it's declared as a protected + // preference here. + 15, user_prefs::kPreferenceResetTime, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + // kSyncRemainingRollbackTries is deprecated and will be removed a few + // releases after M50. + {18, prefs::kSafeBrowsingIncidentsSent, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #if defined(OS_WIN) - { - 19, prefs::kSwReporterPromptVersion, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {19, prefs::kSwReporterPromptVersion, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #endif - // This pref is deprecated and will be removed a few releases after M43. - // kGoogleServicesAccountId replaces it. - { - 21, prefs::kGoogleServicesUsername, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_PERSONAL - }, + // This pref is deprecated and will be removed a few releases after M43. + // kGoogleServicesAccountId replaces it. + {21, prefs::kGoogleServicesUsername, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL}, #if defined(OS_WIN) - { - 22, prefs::kSwReporterPromptSeed, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {22, prefs::kSwReporterPromptSeed, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, #endif - { - 23, prefs::kGoogleServicesAccountId, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_PERSONAL - }, - { - 24, prefs::kGoogleServicesLastAccountId, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_PERSONAL - }, + {23, prefs::kGoogleServicesAccountId, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL}, + {24, prefs::kGoogleServicesLastAccountId, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL}, #if defined(OS_WIN) - { - 25, prefs::kSettingsResetPromptPromptWave, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 26, prefs::kSettingsResetPromptLastTriggeredForDefaultSearch, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 27, prefs::kSettingsResetPromptLastTriggeredForStartupUrls, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, - { - 28, prefs::kSettingsResetPromptLastTriggeredForHomepage, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL - }, + {25, prefs::kSettingsResetPromptPromptWave, + EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC, + ValueType::IMPERSONAL}, + {26, prefs::kSettingsResetPromptLastTriggeredForDefaultSearch, + EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC, + ValueType::IMPERSONAL}, + {27, prefs::kSettingsResetPromptLastTriggeredForStartupUrls, + EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC, + ValueType::IMPERSONAL}, + {28, prefs::kSettingsResetPromptLastTriggeredForHomepage, + EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC, + ValueType::IMPERSONAL}, #endif // defined(OS_WIN) - // See note at top, new items added here also need to be added to - // histograms.xml's TrackedPreference enum. + + // See note at top, new items added here also need to be added to + // histograms.xml's TrackedPreference enum. }; // One more than the last tracked preferences ID above. @@ -342,20 +268,20 @@ if (GROUP_NO_ENFORCEMENT == enforcement_group) { // Remove enforcement for all tracked preferences. - data.enforcement_level = PrefHashFilter::NO_ENFORCEMENT; + data.enforcement_level = EnforcementLevel::NO_ENFORCEMENT; } if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_DSE && data.name == DefaultSearchManager::kDefaultSearchProviderDataPrefName) { // Specifically enable default search settings enforcement. - data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD; + data.enforcement_level = EnforcementLevel::ENFORCE_ON_LOAD; } #if BUILDFLAG(ENABLE_EXTENSIONS) if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE && data.name == extensions::pref_names::kExtensions) { // Specifically enable extension settings enforcement. - data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD; + data.enforcement_level = EnforcementLevel::ENFORCE_ON_LOAD; } #endif
diff --git a/chrome/browser/prefs/profile_pref_store_manager.cc b/chrome/browser/prefs/profile_pref_store_manager.cc index 891e7be..4310f9f1 100644 --- a/chrome/browser/prefs/profile_pref_store_manager.cc +++ b/chrome/browser/prefs/profile_pref_store_manager.cc
@@ -120,7 +120,8 @@ it = tracking_configuration_.begin(); it != tracking_configuration_.end(); ++it) { - if (it->enforcement_level > PrefHashFilter::NO_ENFORCEMENT) { + if (it->enforcement_level > + PrefHashFilter::EnforcementLevel::NO_ENFORCEMENT) { protected_configuration.push_back(*it); protected_pref_names.insert(it->name); } else { @@ -147,11 +148,8 @@ scoped_refptr<JsonPrefStore> unprotected_pref_store(new JsonPrefStore( profile_path_.Append(chrome::kPreferencesFilename), io_task_runner.get(), std::move(unprotected_pref_hash_filter))); - // TODO(gab): Remove kDeprecatedProtectedPreferencesFilename as an alternate - // file in M40+. scoped_refptr<JsonPrefStore> protected_pref_store(new JsonPrefStore( profile_path_.Append(chrome::kSecurePreferencesFilename), - profile_path_.Append(chrome::kProtectedPreferencesFilenameDeprecated), io_task_runner.get(), std::move(protected_pref_hash_filter))); SetupTrackedPreferencesMigration(
diff --git a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc index 60c4165..62d22de8 100644 --- a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc +++ b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
@@ -78,10 +78,10 @@ const char kGoodbyeWorld[] = "GOODBYEWORLD"; const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { - {0u, kTrackedAtomic, PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}, - {1u, kProtectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}}; + {0u, kTrackedAtomic, PrefHashFilter::EnforcementLevel::NO_ENFORCEMENT, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}, + {1u, kProtectedAtomic, PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}}; const size_t kExtraReportingId = 2u; const size_t kReportingIdCount = 3u; @@ -106,7 +106,7 @@ for (const PrefHashFilter::TrackedPreferenceMetadata* it = kConfiguration; it != kConfiguration + arraysize(kConfiguration); ++it) { - if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { + if (it->strategy == PrefHashFilter::PrefTrackingStrategy::ATOMIC) { profile_pref_registry_->RegisterStringPref(it->name, std::string()); } else { profile_pref_registry_->RegisterDictionaryPref(it->name); @@ -119,11 +119,11 @@ // SegregatedPrefStore. Only declare it after configured prefs have been // registered above for this test as kPreferenceResetTime is already // registered in ProfilePrefStoreManager::RegisterProfilePrefs. - PrefHashFilter::TrackedPreferenceMetadata pref_reset_time_config = - {configuration_.rbegin()->reporting_id + 1, - user_prefs::kPreferenceResetTime, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; + PrefHashFilter::TrackedPreferenceMetadata pref_reset_time_config = { + configuration_.rbegin()->reporting_id + 1, + user_prefs::kPreferenceResetTime, + PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}; configuration_.push_back(pref_reset_time_config); ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); @@ -358,8 +358,9 @@ // Now update the configuration to protect it. PrefHashFilter::TrackedPreferenceMetadata new_protected = { - kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; + kExtraReportingId, kUnprotectedPref, + PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}; configuration_.push_back(new_protected); ReloadConfiguration(); @@ -391,7 +392,7 @@ configuration_.begin(); it != configuration_.end(); ++it) { - it->enforcement_level = PrefHashFilter::NO_ENFORCEMENT; + it->enforcement_level = PrefHashFilter::EnforcementLevel::NO_ENFORCEMENT; } ReloadConfiguration(); @@ -409,8 +410,9 @@ // Now introduce protection, including the never-before tracked "new_pref". configuration_ = original_configuration; PrefHashFilter::TrackedPreferenceMetadata new_protected = { - kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; + kExtraReportingId, kUnprotectedPref, + PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}; configuration_.push_back(new_protected); ReloadConfiguration(); @@ -431,8 +433,9 @@ // Now update the configuration to protect it. PrefHashFilter::TrackedPreferenceMetadata new_protected = { - kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; + kExtraReportingId, kUnprotectedPref, + PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD, + PrefHashFilter::PrefTrackingStrategy::ATOMIC}; configuration_.push_back(new_protected); seed_ = "new-seed-to-break-trust"; ReloadConfiguration(); @@ -464,7 +467,7 @@ it != configuration_.end(); ++it) { if (it->name == kProtectedAtomic) { - it->enforcement_level = PrefHashFilter::NO_ENFORCEMENT; + it->enforcement_level = PrefHashFilter::EnforcementLevel::NO_ENFORCEMENT; break; } }
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc index 2744825..1b5fd90 100644 --- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc +++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -221,7 +221,7 @@ // Sanity check that old protected pref file is never present in modern // Chromes. EXPECT_FALSE(base::PathExists( - profile_dir.Append(chrome::kProtectedPreferencesFilenameDeprecated))); + profile_dir.Append(FILE_PATH_LITERAL("Protected Preferences")))); // Read the preferences from disk.
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc index 5f6053ac..59eb8f24 100644 --- a/chrome/browser/printing/print_view_manager.cc +++ b/chrome/browser/printing/print_view_manager.cc
@@ -136,7 +136,8 @@ void PrintViewManager::PrintPreviewDone() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_NE(NOT_PREVIEWING, print_preview_state_); + if (print_preview_state_ == NOT_PREVIEWING) + return; if (print_preview_state_ == SCRIPTED_PREVIEW) { auto& map = g_scripted_print_preview_closure_map.Get(); @@ -161,7 +162,7 @@ void PrintViewManager::RenderFrameDeleted( content::RenderFrameHost* render_frame_host) { if (render_frame_host == print_preview_rfh_) - print_preview_state_ = NOT_PREVIEWING; + PrintPreviewDone(); PrintViewManagerBase::RenderFrameDeleted(render_frame_host); }
diff --git a/chrome/browser/printing/print_view_manager_unittest.cc b/chrome/browser/printing/print_view_manager_unittest.cc new file mode 100644 index 0000000..aa8469d --- /dev/null +++ b/chrome/browser/printing/print_view_manager_unittest.cc
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/printing/print_view_manager.h" +#include "chrome/browser/printing/print_preview_test.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/test/test_renderer_host.h" + +namespace printing { + +using PrintViewManagerTest = PrintPreviewTest; + +TEST_F(PrintViewManagerTest, PrintSubFrameAndDestroy) { + chrome::NewTab(browser()); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(web_contents); + + content::RenderFrameHost* sub_frame = + content::RenderFrameHostTester::For(web_contents->GetMainFrame()) + ->AppendChild("child"); + + PrintViewManager* print_view_manager = + PrintViewManager::FromWebContents(web_contents); + ASSERT_TRUE(print_view_manager); + EXPECT_FALSE(print_view_manager->print_preview_rfh()); + + print_view_manager->PrintPreviewNow(sub_frame, false); + EXPECT_TRUE(print_view_manager->print_preview_rfh()); + + content::RenderFrameHostTester::For(sub_frame)->Detach(); + EXPECT_FALSE(print_view_manager->print_preview_rfh()); +} + +} // namespace printing
diff --git a/chrome/browser/resources/net_internals/source_entry.js b/chrome/browser/resources/net_internals/source_entry.js index 25f0e81b..126750c 100644 --- a/chrome/browser/resources/net_internals/source_entry.js +++ b/chrome/browser/resources/net_internals/source_entry.js
@@ -82,6 +82,7 @@ case EventSourceType.SOCKET_STREAM: case EventSourceType.HTTP_STREAM_JOB: case EventSourceType.HTTP_STREAM_JOB_CONTROLLER: + case EventSourceType.BIDIRECTIONAL_STREAM: this.description_ = e.params.url; break; // TODO(davidben): Remove CONNECT_JOB after M57 is released.
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html index 2ef0b67..fe1e45a2 100644 --- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html +++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -26,7 +26,7 @@ font-size:[[computeMinimumFontSize_( prefs.webkit.webprefs.minimum_font_size.value)]]px; font-family: - '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';" + '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';"> <span>[[ computeMinimumFontSize_( prefs.webkit.webprefs.minimum_font_size.value)]]</span> @@ -39,83 +39,87 @@ </cr-slider> </div> <div class="settings-box"> - <div class="start"> - <h2>$i18n{standardFont}</h2> - <div class="list-frame"> - <div class="list-item"> - <settings-dropdown-menu class="start" - pref="{{prefs.webkit.webprefs.fonts.standard.Zyyy}}" - menu-options="[[fontOptions_]]"> - </settings-dropdown-menu> - </div> - <div class="list-item underbar" - style=" - font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; - font-family: - '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';" - <span> - [[prefs.webkit.webprefs.default_font_size.value]]: - $i18n{quickBrownFox} - </span> - </div> - </div> - <h2>$i18n{serifFont}</h2> - <div class="list-frame"> - <div class="list-item"> - <settings-dropdown-menu class="start" - pref="{{prefs.webkit.webprefs.fonts.serif.Zyyy}}" - menu-options="[[fontOptions_]]"> - </settings-dropdown-menu> - </div> - <div class="list-item underbar" - style=" - font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; - font-family: - '[[prefs.webkit.webprefs.fonts.serif.Zyyy.value]]';" - <span> - [[prefs.webkit.webprefs.default_font_size.value]]: - $i18n{quickBrownFox} - </span> - </div> - </div> - <h2>$i18n{sansSerifFont}</h2> - <div class="list-frame"> - <div class="list-item"> - <settings-dropdown-menu class="start" - pref="{{prefs.webkit.webprefs.fonts.sansserif.Zyyy}}" - menu-options="[[fontOptions_]]"> - </settings-dropdown-menu> - </div> - <div class="list-item underbar" - style=" - font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; - font-family: - '[[prefs.webkit.webprefs.fonts.sansserif.Zyyy.value]]';" - <span> - [[prefs.webkit.webprefs.default_font_size.value]]: - $i18n{quickBrownFox} - </span> - </div> - </div> - <h2>$i18n{fixedWidthFont}</h2> - <div class="list-frame"> - <div class="list-item"> - <settings-dropdown-menu class="start" - pref="{{prefs.webkit.webprefs.fonts.fixed.Zyyy}}" - menu-options="[[fontOptions_]]"> - </settings-dropdown-menu> - </div> - <div class="list-item" - style=" - font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; - font-family: - '[[prefs.webkit.webprefs.fonts.fixed.Zyyy.value]]';" - <span> - [[prefs.webkit.webprefs.default_font_size.value]]: - $i18n{quickBrownFox} - </span> - </div> - </div> + <h2>$i18n{standardFont}</h2> + </div> + <div class="list-frame"> + <div class="list-item"> + <settings-dropdown-menu class="start" + pref="{{prefs.webkit.webprefs.fonts.standard.Zyyy}}" + menu-options="[[fontOptions_]]"> + </settings-dropdown-menu> + </div> + <div class="list-item underbar" + style=" + font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; + font-family: + '[[prefs.webkit.webprefs.fonts.standard.Zyyy.value]]';"> + <span> + [[prefs.webkit.webprefs.default_font_size.value]]: + $i18n{quickBrownFox} + </span> + </div> + </div> + <div class="settings-box"> + <h2>$i18n{serifFont}</h2> + </div> + <div class="list-frame"> + <div class="list-item"> + <settings-dropdown-menu class="start" + pref="{{prefs.webkit.webprefs.fonts.serif.Zyyy}}" + menu-options="[[fontOptions_]]"> + </settings-dropdown-menu> + </div> + <div class="list-item underbar" + style=" + font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; + font-family: + '[[prefs.webkit.webprefs.fonts.serif.Zyyy.value]]';"> + <span> + [[prefs.webkit.webprefs.default_font_size.value]]: + $i18n{quickBrownFox} + </span> + </div> + </div> + <div class="settings-box"> + <h2>$i18n{sansSerifFont}</h2> + </div> + <div class="list-frame"> + <div class="list-item"> + <settings-dropdown-menu class="start" + pref="{{prefs.webkit.webprefs.fonts.sansserif.Zyyy}}" + menu-options="[[fontOptions_]]"> + </settings-dropdown-menu> + </div> + <div class="list-item underbar" + style=" + font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; + font-family: + '[[prefs.webkit.webprefs.fonts.sansserif.Zyyy.value]]';"> + <span> + [[prefs.webkit.webprefs.default_font_size.value]]: + $i18n{quickBrownFox} + </span> + </div> + </div> + <div class="settings-box"> + <h2>$i18n{fixedWidthFont}</h2> + </div> + <div class="list-frame"> + <div class="list-item"> + <settings-dropdown-menu class="start" + pref="{{prefs.webkit.webprefs.fonts.fixed.Zyyy}}" + menu-options="[[fontOptions_]]"> + </settings-dropdown-menu> + </div> + <div class="list-item" + style=" + font-size:[[prefs.webkit.webprefs.default_font_size.value]]px; + font-family: + '[[prefs.webkit.webprefs.fonts.fixed.Zyyy.value]]';"> + <span> + [[prefs.webkit.webprefs.default_font_size.value]]: + $i18n{quickBrownFox} + </span> </div> </div> <template is="dom-if" if="[[!isGuest_]]">
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp index b8b4242c..252bb8a 100644 --- a/chrome/browser/resources/settings/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -48,6 +48,7 @@ 'target_name': 'route', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', ], 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], },
diff --git a/chrome/browser/resources/settings/route.html b/chrome/browser/resources/settings/route.html index 102248e..1300e857 100644 --- a/chrome/browser/resources/settings/route.html +++ b/chrome/browser/resources/settings/route.html
@@ -1,3 +1,4 @@ <link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="i18n_setup.html"> <script src="route.js"></script>
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index 87a714c..7d02247ac 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -148,9 +148,12 @@ r.CERTIFICATES = r.PRIVACY.createChild('/certificates'); r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); - r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); - r.SITE_SETTINGS_SITE_DETAILS = - r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); + + if (loadTimeData.getBoolean('enableSiteSettings')) { + r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); + r.SITE_SETTINGS_SITE_DETAILS = + r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); + } r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers');
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html index 268aff11..fa13cad 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.html +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -30,7 +30,7 @@ }; -webkit-user-select: none; background-color: var(--settings-background-color); - color: var(--paper-grey-800); + color: var(--paper-grey-900); display: flex; flex-direction: column; line-height: 154%; /* Apply 20px line-height to all texts by default. */
diff --git a/chrome/browser/resources/settings/site_settings/zoom_levels.html b/chrome/browser/resources/settings/site_settings/zoom_levels.html index 2e2df3e0..f817afb0 100644 --- a/chrome/browser/resources/settings/site_settings/zoom_levels.html +++ b/chrome/browser/resources/settings/site_settings/zoom_levels.html
@@ -16,6 +16,7 @@ .zoom-label { -webkit-margin-end: 16px; + color: var(--paper-grey-600); } .empty-message {
diff --git a/chrome/browser/safe_browsing/permission_reporter_browsertest.cc b/chrome/browser/safe_browsing/permission_reporter_browsertest.cc index 678c15c..00d89850 100644 --- a/chrome/browser/safe_browsing/permission_reporter_browsertest.cc +++ b/chrome/browser/safe_browsing/permission_reporter_browsertest.cc
@@ -17,8 +17,8 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" #include "chrome/common/safe_browsing/permission_report.pb.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc index afdcd87c..57072b8 100644 --- a/chrome/browser/shell_integration_linux.cc +++ b/chrome/browser/shell_integration_linux.cc
@@ -164,26 +164,27 @@ #endif } -#if !defined(OS_CHROMEOS) -// If |check| is true, returns the output of "xdg-settings check {property} -// *.desktop", otherwise returns the output of "xdg-settings get {property}", -// where property is "default-web-browser" if |protocol| is empty or -// "default-url-scheme-handler |protocol|" otherwise. Returns "" if -// xdg-settings fails for any reason. -std::string GetXdgSettingsOutput(bool check, - const std::string& protocol, - base::Environment* env) { +// If |protocol| is empty this function checks if Chrome is the default browser, +// otherwise it checks if Chrome is the default handler application for +// |protocol|. +DefaultWebClientState GetIsDefaultWebClient(const std::string& protocol) { +#if defined(OS_CHROMEOS) + return UNKNOWN_DEFAULT; +#else + base::ThreadRestrictions::AssertIOAllowed(); + + std::unique_ptr<base::Environment> env(base::Environment::Create()); + std::vector<std::string> argv; argv.push_back(kXdgSettings); - argv.push_back(check ? "check" : "get"); + argv.push_back("check"); if (protocol.empty()) { argv.push_back(kXdgSettingsDefaultBrowser); } else { argv.push_back(kXdgSettingsDefaultSchemeHandler); argv.push_back(protocol); } - if (check) - argv.push_back(shell_integration_linux::GetDesktopName(env)); + argv.push_back(shell_integration_linux::GetDesktopName(env.get())); std::string reply; int success_code; @@ -196,47 +197,15 @@ } } - if (!ran_ok || success_code != EXIT_SUCCESS) - return std::string(); - - return reply; -} -#endif - -// If |protocol| is empty this function checks if Chrome is the default browser, -// otherwise it checks if Chrome is the default handler application for -// |protocol|. -DefaultWebClientState GetDefaultWebClient(const std::string& protocol) { -#if defined(OS_CHROMEOS) - return UNKNOWN_DEFAULT; -#else - base::ThreadRestrictions::AssertIOAllowed(); - - std::unique_ptr<base::Environment> env(base::Environment::Create()); - std::string xdg_is_default = GetXdgSettingsOutput(true, protocol, env.get()); - if (base::StartsWith(xdg_is_default, "yes", base::CompareCase::SENSITIVE)) { - return IS_DEFAULT; - } - if (base::StartsWith(xdg_is_default, "no", base::CompareCase::SENSITIVE)) { - // An output of "no" does not necessarily mean Chrom[e,ium] is not the - // default. According to the xdg-settings man page, this can happen when - // "only some of the underlying settings actually reflect that value". Don't - // return NOT_DEFAULT unless we're sure, or else an annoying "Chrome is not - // your default browser" banner will appear on every launch - // (https://crbug.com/578888). - if (base::StartsWith(GetXdgSettingsOutput(false, protocol, env.get()), - shell_integration_linux::GetDesktopName(env.get()), - base::CompareCase::SENSITIVE)) { - // This is the odd case where 'xdg-settings check' said that Chrome wasn't - // the default, but 'xdg-settings get' returned Chrome as the default. - return UNKNOWN_DEFAULT; - } - // xdg-settings says the default is non-Chrome, and is self-consistent. - return NOT_DEFAULT; + if (!ran_ok || success_code != EXIT_SUCCESS) { + // xdg-settings failed: we can't determine or set the default browser. + return UNKNOWN_DEFAULT; } - // xdg-settings failed: we can't determine or set the default browser. - return UNKNOWN_DEFAULT; + // Allow any reply that starts with "yes". + return base::StartsWith(reply, "yes", base::CompareCase::SENSITIVE) + ? IS_DEFAULT + : NOT_DEFAULT; #endif } @@ -274,7 +243,7 @@ } DefaultWebClientState GetDefaultBrowser() { - return GetDefaultWebClient(std::string()); + return GetIsDefaultWebClient(std::string()); } bool IsFirefoxDefaultBrowser() { @@ -290,7 +259,7 @@ } DefaultWebClientState IsDefaultProtocolClient(const std::string& protocol) { - return GetDefaultWebClient(protocol); + return GetIsDefaultWebClient(protocol); } } // namespace shell_integration
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 138012a..c85832b 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -127,6 +127,7 @@ "passwords/password_manager_presenter.cc", "passwords/password_manager_presenter.h", "passwords/password_ui_view.h", + "permission_bubble/permission_prompt.h", "platform_keys_certificate_selector_chromeos.h", "prefs/prefs_tab_helper.cc", "prefs/prefs_tab_helper.h", @@ -197,7 +198,6 @@ "views/platform_keys_certificate_selector_chromeos.cc", "views/platform_keys_certificate_selector_chromeos.h", "web_contents_sizer.h", - "website_settings/permission_prompt.h", "webui/about_ui.cc", "webui/about_ui.h", "webui/bluetooth_internals/bluetooth_internals_ui.cc", @@ -759,8 +759,6 @@ "layout_constants.h", "location_bar/location_bar.cc", "location_bar/location_bar.h", - "location_bar/location_bar_util.cc", - "location_bar/location_bar_util.h", "native_window_tracker.h", "omnibox/alternate_nav_infobar_delegate.cc", "omnibox/alternate_nav_infobar_delegate.h", @@ -795,6 +793,8 @@ "pdf/adobe_reader_info_win.h", "pdf/chrome_pdf_web_contents_helper_client.cc", "pdf/chrome_pdf_web_contents_helper_client.h", + "permission_bubble/chooser_bubble_delegate.cc", + "permission_bubble/chooser_bubble_delegate.h", "sad_tab.cc", "sad_tab.h", "sad_tab_helper.cc", @@ -899,8 +899,6 @@ "unload_controller_web_contents_delegate.h", "user_manager.cc", "user_manager.h", - "website_settings/chooser_bubble_delegate.cc", - "website_settings/chooser_bubble_delegate.h", "webui/app_launcher_login_handler.cc", "webui/app_launcher_login_handler.h", "webui/bookmarks_ui.cc", @@ -1547,6 +1545,8 @@ "views/payments/validation_delegate.h", "views/payments/view_stack.cc", "views/payments/view_stack.h", + "views/permission_bubble/permission_prompt_impl.cc", + "views/permission_bubble/permission_prompt_impl.h", "views/subtle_notification_view.cc", "views/subtle_notification_view.h", "views/sync/bubble_sync_promo_view.cc", @@ -1559,8 +1559,6 @@ "views/toolbar/toolbar_actions_bar_bubble_views.h", "views/update_recommended_message_box.cc", "views/update_recommended_message_box.h", - "views/website_settings/permission_prompt_impl.cc", - "views/website_settings/permission_prompt_impl.h", ] deps += [ "//chrome/browser/ui/views", @@ -1815,6 +1813,9 @@ "views/passwords/manage_passwords_bubble_view.h", "views/passwords/manage_passwords_icon_views.cc", "views/passwords/manage_passwords_icon_views.h", + "views/permission_bubble/chooser_bubble_ui_view.cc", + "views/permission_bubble/chooser_bubble_ui_view.h", + "views/permission_bubble/permission_prompt_impl_views.cc", "views/process_singleton_dialog_linux.cc", "views/profiles/profile_indicator_icon.cc", "views/profiles/profile_indicator_icon.h", @@ -1898,9 +1899,6 @@ "views/validation_message_bubble_view.h", "views/webshare/webshare_target_picker_view.cc", "views/webshare/webshare_target_picker_view.h", - "views/website_settings/chooser_bubble_ui_view.cc", - "views/website_settings/chooser_bubble_ui_view.h", - "views/website_settings/permission_prompt_impl_views.cc", ] if (use_aura) { @@ -2884,6 +2882,13 @@ "cocoa/passwords/signin_promo_view_controller.mm", "cocoa/passwords/update_pending_password_view_controller.h", "cocoa/passwords/update_pending_password_view_controller.mm", + "cocoa/permission_bubble/chooser_bubble_ui_cocoa.h", + "cocoa/permission_bubble/chooser_bubble_ui_cocoa.mm", + "cocoa/permission_bubble/permission_bubble_cocoa.h", + "cocoa/permission_bubble/permission_bubble_cocoa.mm", + "cocoa/permission_bubble/permission_bubble_controller.h", + "cocoa/permission_bubble/permission_bubble_controller.mm", + "cocoa/permission_bubble/permission_prompt_impl_views_mac.mm", "cocoa/profiles/avatar_base_controller.h", "cocoa/profiles/avatar_base_controller.mm", "cocoa/profiles/avatar_button.h", @@ -2988,13 +2993,6 @@ "cocoa/view_resizer.h", "cocoa/web_contents_modal_dialog_manager_views_mac.h", "cocoa/web_contents_modal_dialog_manager_views_mac.mm", - "cocoa/website_settings/chooser_bubble_ui_cocoa.h", - "cocoa/website_settings/chooser_bubble_ui_cocoa.mm", - "cocoa/website_settings/permission_bubble_cocoa.h", - "cocoa/website_settings/permission_bubble_cocoa.mm", - "cocoa/website_settings/permission_bubble_controller.h", - "cocoa/website_settings/permission_bubble_controller.mm", - "cocoa/website_settings/permission_prompt_impl_views_mac.mm", "cocoa/window_size_autosaver.h", "cocoa/window_size_autosaver.mm",
diff --git a/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.cc b/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.cc index 66c7b91f..4b709f1 100644 --- a/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.cc +++ b/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.cc
@@ -6,7 +6,7 @@ #include <stddef.h> #include <utility> - +#include "chrome/browser/content_settings/chrome_content_settings_utils.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" @@ -49,6 +49,9 @@ } infobar_service->AddInfoBar(std::move(infobar)); + + content_settings::RecordPopupsAction( + content_settings::POPUPS_ACTION_DISPLAYED_INFOBAR_ON_MOBILE); } PopupBlockedInfoBarDelegate::~PopupBlockedInfoBarDelegate() { @@ -116,5 +119,7 @@ it != blocked_popups.end(); ++it) popup_blocker_helper->ShowBlockedPopup(it->first); + content_settings::RecordPopupsAction( + content_settings::POPUPS_ACTION_CLICKED_ALWAYS_SHOW_ON_MOBILE); return true; }
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc index f888755..dfd61ec 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_icon.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -172,6 +172,7 @@ // ImageDecoder::ImageRequest void OnImageDecoded(const SkBitmap& bitmap) override; void OnDecodeImageFailed() override; + private: base::WeakPtr<ArcAppIcon> host_; int dimension_; @@ -206,6 +207,8 @@ VLOG(2) << "Decoded ARC icon has unexpected dimension " << bitmap.width() << "x" << bitmap.height() << ". Expected " << expected_dim << "x" << "."; + + host_->MaybeRequestIcon(scale_factor_); host_->DiscardDecodeRequest(this); return; } @@ -214,7 +217,6 @@ image_skia.AddRepresentation(gfx::ImageSkiaRep( bitmap, ui::GetScaleForScaleFactor(scale_factor_))); - host_->Update(&image_skia); host_->DiscardDecodeRequest(this); } @@ -225,6 +227,7 @@ if (!host_) return; + host_->MaybeRequestIcon(scale_factor_); host_->DiscardDecodeRequest(this); } @@ -270,7 +273,7 @@ base::Bind(&ArcAppIcon::OnIconRead, weak_ptr_factory_.GetWeakPtr())); } -void ArcAppIcon::RequestIcon(ui::ScaleFactor scale_factor) { +void ArcAppIcon::MaybeRequestIcon(ui::ScaleFactor scale_factor) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_); DCHECK(prefs); @@ -278,7 +281,7 @@ // ArcAppListPrefs notifies ArcAppModelBuilder via Observer when icon is ready // and ArcAppModelBuilder refreshes the icon of the corresponding item by // calling LoadScaleFactor. - prefs->RequestIcon(app_id_, scale_factor); + prefs->MaybeRequestIcon(app_id_, scale_factor); } // static @@ -293,24 +296,29 @@ path_to_read = path; } else { if (default_app_path.empty() || !base::PathExists(default_app_path)) { - return base::WrapUnique(new ArcAppIcon::ReadResult( - false, true, scale_factor, std::string())); + return base::MakeUnique<ArcAppIcon::ReadResult>(false, true, scale_factor, + std::string()); } path_to_read = default_app_path; } + bool request_to_install = path_to_read != path; + // Read the file from disk. std::string unsafe_icon_data; - if (!base::ReadFileToString(path_to_read, &unsafe_icon_data)) { + if (!base::ReadFileToString(path_to_read, &unsafe_icon_data) || + unsafe_icon_data.empty()) { VLOG(2) << "Failed to read an ARC icon from file " << path.MaybeAsASCII(); - return base::WrapUnique(new ArcAppIcon::ReadResult( - true, path_to_read != path, scale_factor, std::string())); + + // If |unsafe_icon_data| is empty typically means we have a file corruption + // on cached icon file. Send request to re install the icon. + request_to_install |= unsafe_icon_data.empty(); + return base::MakeUnique<ArcAppIcon::ReadResult>( + true, request_to_install, scale_factor, std::string()); } - return base::WrapUnique(new ArcAppIcon::ReadResult(false, - path_to_read != path, - scale_factor, - unsafe_icon_data)); + return base::MakeUnique<ArcAppIcon::ReadResult>( + false, request_to_install, scale_factor, unsafe_icon_data); } void ArcAppIcon::OnIconRead( @@ -318,7 +326,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (read_result->request_to_install) - RequestIcon(read_result->scale_factor); + MaybeRequestIcon(read_result->scale_factor); if (!read_result->unsafe_icon_data.empty()) { decode_requests_.push_back(base::MakeUnique<DecodeRequest>(
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.h b/chrome/browser/ui/app_list/arc/arc_app_icon.h index 69e2a1b..2d4c618 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_icon.h +++ b/chrome/browser/ui/app_list/arc/arc_app_icon.h
@@ -82,7 +82,7 @@ class DecodeRequest; struct ReadResult; - void RequestIcon(ui::ScaleFactor scale_factor); + void MaybeRequestIcon(ui::ScaleFactor scale_factor); static std::unique_ptr<ArcAppIcon::ReadResult> ReadOnFileThread( ui::ScaleFactor scale_factor, const base::FilePath& path,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc index 7a5f456..294e5ed 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -317,6 +317,23 @@ return ToIconPath(GetAppPath(app_id), scale_factor); } +bool ArcAppListPrefs::IsIconRequestRecorded( + const std::string& app_id, + ui::ScaleFactor scale_factor) const { + const auto iter = request_icon_recorded_.find(app_id); + if (iter == request_icon_recorded_.end()) + return false; + return iter->second & (1 << scale_factor); +} + +void ArcAppListPrefs::MaybeRemoveIconRequestRecord(const std::string& app_id) { + request_icon_recorded_.erase(app_id); +} + +void ArcAppListPrefs::ClearIconRequestRecord() { + request_icon_recorded_.clear(); +} + void ArcAppListPrefs::RequestIcon(const std::string& app_id, ui::ScaleFactor scale_factor) { // ArcSessionManager can be terminated during test tear down, before callback @@ -330,12 +347,14 @@ return; } - // In case app is not ready, defer this request. - if (!ready_apps_.count(app_id)) { - request_icon_deferred_[app_id] = - request_icon_deferred_[app_id] | 1 << scale_factor; + // In case app is not ready, recorded request will be send to ARC when app + // becomes ready. + // This record will prevent ArcAppIcon from resending request to ARC for app + // icon when icon file decode failure is suffered in case app sends bad icon. + request_icon_recorded_[app_id] |= (1 << scale_factor); + + if (!ready_apps_.count(app_id)) return; - } if (!app_instance_holder_->has_instance()) { // AppInstance should be ready since we have app_id in ready_apps_. This @@ -371,6 +390,12 @@ } } +void ArcAppListPrefs::MaybeRequestIcon(const std::string& app_id, + ui::ScaleFactor scale_factor) { + if (!IsIconRequestRecorded(app_id, scale_factor)) + RequestIcon(app_id, scale_factor); +} + void ArcAppListPrefs::SetNotificationsEnabled(const std::string& app_id, bool enabled) { if (!IsRegistered(app_id)) { @@ -739,6 +764,7 @@ default_apps_installations_.clear(); detect_default_app_availability_timeout_.Stop(); binding_.Close(); + ClearIconRequestRecord(); if (sync_service_) { sync_service_->StopSyncing(syncer::ARC_PACKAGE); @@ -837,14 +863,13 @@ } if (app_ready) { - auto deferred_icons = request_icon_deferred_.find(app_id); - if (deferred_icons != request_icon_deferred_.end()) { + auto pending_icons = request_icon_recorded_.find(app_id); + if (pending_icons != request_icon_recorded_.end()) { for (uint32_t i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) { - if (deferred_icons->second & (1 << i)) { + if (pending_icons->second & (1 << i)) { RequestIcon(app_id, static_cast<ui::ScaleFactor>(i)); } } - request_icon_deferred_.erase(deferred_icons); } bool deferred_notifications_enabled; @@ -862,6 +887,8 @@ arc::RemoveCachedIcon(app_info->icon_resource_id); } + MaybeRemoveIconRequestRecord(app_id); + // From now, app is not available. ready_apps_.erase(app_id);
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h index cc30435..0529948 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -199,11 +199,9 @@ // Sets last launched time for the requested app. void SetLastLaunchTime(const std::string& app_id, const base::Time& time); - // Requests to load an app icon for specific scale factor. If the app or ARC - // bridge service is not ready, then defer this request until the app gets - // available. Once new icon is installed notifies an observer - // OnAppIconUpdated. - void RequestIcon(const std::string& app_id, ui::ScaleFactor scale_factor); + // Calls RequestIcon if no request is recorded. + void MaybeRequestIcon(const std::string& app_id, + ui::ScaleFactor scale_factor); // Sets notification enabled flag for given value. If the app or ARC bridge // service is not ready, then defer this request until the app gets @@ -249,6 +247,7 @@ private: friend class ChromeLauncherControllerImplTest; + friend class ArcAppModelBuilderTest; // See the Create methods. ArcAppListPrefs( @@ -343,6 +342,12 @@ ui::ScaleFactor scale_factor, bool install_succeed); + // Requests to load an app icon for specific scale factor. If the app or ARC + // bridge service is not ready, then defer this request until the app gets + // available. Once new icon is installed notifies an observer + // OnAppIconUpdated. + void RequestIcon(const std::string& app_id, ui::ScaleFactor scale_factor); + // This checks if app is not registered yet and in this case creates // non-launchable app entry. void MaybeAddNonLaunchableApp(const base::Optional<std::string>& name, @@ -369,6 +374,14 @@ // some default app is not available yet. void MaybeSetDefaultAppLoadingTimeout(); + bool IsIconRequestRecorded(const std::string& app_id, + ui::ScaleFactor scale_factor) const; + + // Remove the IconRequestRecord associated with app_id. + void MaybeRemoveIconRequestRecord(const std::string& app_id); + + void ClearIconRequestRecord(); + Profile* const profile_; // Owned by the BrowserContext. @@ -387,10 +400,15 @@ std::unordered_set<std::string> tracked_apps_; // Contains number of ARC packages that are currently installing. int installing_packages_count_ = 0; - // Keeps deferred icon load requests. Each app may contain several requests - // for different scale factor. Scale factor is defined by specific bit - // position. - std::map<std::string, uint32_t> request_icon_deferred_; + // Keeps record for icon request. Each app may contain several requests for + // different scale factor. Scale factor is defined by specific bit position. + // Mainly two usages: + // 1. Keeps deferred icon load requests when apps are not ready. Request will + // be sent when apps becomes ready. + // 2. Keeps record of icon request sent to Android. In each user session, one + // request per app per scale_factor is allowed once. + // When ARC is disabled or the app is uninstalled, the record will be erased. + std::map<std::string, uint32_t> request_icon_recorded_; // True if this preference has been initialized once. bool is_initialized_ = false; // True if apps were restored.
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 2f66084..4b35b2d 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -373,6 +373,14 @@ } } + // Removes icon request record and allowd re-sending icon request. + void MaybeRemoveIconRequestRecord(const std::string& app_id) { + ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + prefs->MaybeRemoveIconRequestRecord(app_id); + } + void AddPackage(const arc::mojom::ArcPackageInfo& package) { arc_test_.AddPackage(package); } @@ -938,8 +946,6 @@ base::RunLoop().RunUntilIdle(); EXPECT_FALSE(base::PathExists(app_path)); - // Request icon, this will create app folder. - prefs->RequestIcon(app_id, scale_factor); // Now send generated icon for the app. std::string png_data; EXPECT_TRUE(app_instance()->GenerateAndSendIcon( @@ -1092,7 +1098,9 @@ content::BrowserThread::GetBlockingPool()->FlushForTesting(); base::RunLoop().RunUntilIdle(); - // Store number of requests generated during the App List item creation. + // Store number of requests generated during the App List item creation. Same + // request will not be re-sent without clearing the request record in + // ArcAppListPrefs. const size_t initial_icon_request_count = app_instance()->icon_requests().size(); @@ -1130,6 +1138,9 @@ } // Fallback when shortcut is not found for shelf group id, use app id instead. + // Remove the IconRequestRecord for |app_id| to observe the icon request for + // |app_id| is re-sent. + MaybeRemoveIconRequestRecord(app_id); icon_loader.FetchImage(id_shortcut_absent); EXPECT_EQ(2UL, delegate.update_image_cnt()); content::BrowserThread::GetBlockingPool()->FlushForTesting(); @@ -1145,6 +1156,64 @@ } } +// If the cached icon file is corrupted, we expect send request to ARC for a new +// icon. +TEST_P(ArcAppModelBuilderTest, IconLoaderWithBadIcon) { + const arc::mojom::AppInfo& app = fake_apps()[0]; + const std::string app_id = ArcAppTest::GetAppId(app); + + ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + app_instance()->RefreshAppList(); + app_instance()->SendRefreshAppList(std::vector<arc::mojom::AppInfo>( + fake_apps().begin(), fake_apps().begin() + 1)); + content::BrowserThread::GetBlockingPool()->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + + // Store number of requests generated during the App List item creation. Same + // request will not be re-sent without clearing the request record in + // ArcAppListPrefs. + const size_t initial_icon_request_count = + app_instance()->icon_requests().size(); + + FakeAppIconLoaderDelegate delegate; + ArcAppIconLoader icon_loader(profile(), app_list::kListIconSize, &delegate); + icon_loader.FetchImage(app_id); + + content::BrowserThread::GetBlockingPool()->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + // Although icon file is still missing, expect no new request sent to ARC as + // them are recorded in IconRequestRecord in ArcAppListPrefs. + EXPECT_EQ(app_instance()->icon_requests().size(), initial_icon_request_count); + // Validate default image. + ValidateIcon(delegate.image()); + + MaybeRemoveIconRequestRecord(app_id); + + // Install Bad image. + const std::vector<ui::ScaleFactor>& scale_factors = + ui::GetSupportedScaleFactors(); + ArcAppItem* app_item = FindArcItem(app_id); + for (auto& scale_factor : scale_factors) { + app_instance()->GenerateAndSendBadIcon( + app, static_cast<arc::mojom::ScaleFactor>(scale_factor)); + const float scale = ui::GetScaleForScaleFactor(scale_factor); + // Force the icon to be loaded. + app_item->icon().GetRepresentation(scale); + WaitForIconReady(prefs, app_id, scale_factor); + } + // After clear request record related to |app_id|, when bad icon is installed, + // decoding failure will trigger re-sending new icon request to ARC. + EXPECT_TRUE(app_instance()->icon_requests().size() > + initial_icon_request_count); + for (size_t i = initial_icon_request_count; + i < app_instance()->icon_requests().size(); ++i) { + const auto& request = app_instance()->icon_requests()[i]; + EXPECT_TRUE(request->IsForApp(app)); + } +} + // TODO(crbug.com/628425) -- reenable once this test is less flaky. TEST_P(ArcAppModelBuilderTest, DISABLED_IconLoader) { const arc::mojom::AppInfo& app = fake_apps()[0];
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc index db48a06..a6c4bd1 100644 --- a/chrome/browser/ui/app_list/start_page_service.cc +++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -159,21 +159,6 @@ explicit StartPageWebContentsDelegate(Profile* profile) : profile_(profile) {} ~StartPageWebContentsDelegate() override {} - void RequestMediaAccessPermission( - content::WebContents* web_contents, - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback) override { - MediaStreamDevicesController::RequestPermissions(web_contents, request, - callback); - } - - bool CheckMediaAccessPermission(content::WebContents* web_contents, - const GURL& security_origin, - content::MediaStreamType type) override { - return MediaCaptureDevicesDispatcher::GetInstance() - ->CheckMediaAccessPermission(web_contents, security_origin, type); - } - void AddNewContents(content::WebContents* source, content::WebContents* new_contents, WindowOpenDisposition disposition,
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index c2a9f4f..7773489 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -123,6 +123,7 @@ #include "chrome/browser/ui/global_error/global_error_service_factory.h" #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h" #include "chrome/browser/ui/location_bar/location_bar.h" +#include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "chrome/browser/ui/search/search_delegate.h" #include "chrome/browser/ui/search/search_model.h" #include "chrome/browser/ui/search/search_tab_helper.h" @@ -139,7 +140,6 @@ #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/unload_controller.h" #include "chrome/browser/ui/validation_message_bubble.h" -#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/browser/ui/window_sizer/window_sizer.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 65249707..4d7ac82 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -64,6 +64,7 @@ #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #include "chrome/browser/ui/cocoa/l10n_util.h" #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" +#include "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" #import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h" #import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h" #import "chrome/browser/ui/cocoa/profiles/avatar_icon_controller.h" @@ -75,7 +76,6 @@ #import "chrome/browser/ui/cocoa/tabs/tab_view.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #import "chrome/browser/ui/cocoa/translate/translate_bubble_controller.h" -#include "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index c7ae5d7..4936bae1 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -32,12 +32,13 @@ #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h" #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" -#include "chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.h" #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h" +#include "chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.h" #import "chrome/browser/ui/cocoa/fullscreen_window.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" #import "chrome/browser/ui/cocoa/profiles/avatar_button_controller.h" #import "chrome/browser/ui/cocoa/profiles/avatar_icon_controller.h" #import "chrome/browser/ui/cocoa/status_bubble_mac.h" @@ -45,7 +46,6 @@ #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm index 71b9e2d..424c6e1 100644 --- a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm +++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
@@ -4,14 +4,36 @@ #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h" +#include <stddef.h> + +#include "base/i18n/rtl.h" +#include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" #import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" -#include "chrome/browser/ui/location_bar/location_bar_util.h" #include "chrome/grit/generated_resources.h" #include "skia/ext/skia_utils_mac.h" #include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/gfx/color_palette.h" +#include "ui/gfx/text_elider.h" + +namespace { + +// Build a short string to use in keyword-search when the field isn't very big. +base::string16 CalculateMinString(const base::string16& description) { + // Chop at the first '.' or whitespace. + const size_t chop_index = description.find_first_of(base::kWhitespaceUTF16 + + base::ASCIIToUTF16(".")); + base::string16 min_string( + (chop_index == base::string16::npos) + ? gfx::TruncateString(description, 3, gfx::WORD_BREAK) + : description.substr(0, chop_index)); + base::i18n::AdjustStringForLocaleDirection(&min_string); + return min_string; +} + +} // namespace SelectedKeywordDecoration::SelectedKeywordDecoration() { // Note: the unit test @@ -53,8 +75,7 @@ void SelectedKeywordDecoration::SetKeyword(const base::string16& short_name, bool is_extension_keyword) { - const base::string16 min_name( - location_bar_util::CalculateMinString(short_name)); + const base::string16 min_name(CalculateMinString(short_name)); const int keyword_text_id = IDS_OMNIBOX_KEYWORD_TEXT_MD; NSString* full_string =
diff --git a/chrome/browser/ui/cocoa/notifications/BUILD.gn b/chrome/browser/ui/cocoa/notifications/BUILD.gn index 4fb22a7..4ea320f 100644 --- a/chrome/browser/ui/cocoa/notifications/BUILD.gn +++ b/chrome/browser/ui/cocoa/notifications/BUILD.gn
@@ -25,6 +25,7 @@ deps = [ ":common", "//base:base", + "//third_party/crashpad/crashpad/client", ] libs = [ @@ -53,6 +54,8 @@ "notification_delivery.h", "notification_response_builder_mac.h", "notification_response_builder_mac.mm", + "xpc_mach_port.h", + "xpc_mach_port.mm", ] deps = [
diff --git a/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm b/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm index d81f2b6..528e198 100644 --- a/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm +++ b/chrome/browser/ui/cocoa/notifications/alert_notification_service.mm
@@ -8,11 +8,17 @@ #import "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h" #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h" #import "chrome/browser/ui/cocoa/notifications/xpc_transaction_handler.h" +#include "third_party/crashpad/crashpad/client/crashpad_client.h" @class NSUserNotificationCenter; @implementation AlertNotificationService { XPCTransactionHandler* transactionHandler_; + + // Ensures that the XPC service has been configured for crash reporting. + // Other messages should not be sent to a new instance of the service + // before -setMachExceptionPort: is called. + BOOL didSetExceptionPort_; } - (instancetype)initWithTransactionHandler:(XPCTransactionHandler*)handler { @@ -22,7 +28,21 @@ return self; } +- (void)setMachExceptionPort:(CrXPCMachPort*)port { + base::mac::ScopedMachSendRight sendRight([port takeRight]); + if (!sendRight.is_valid()) { + NOTREACHED(); + return; + } + + crashpad::CrashpadClient client; + didSetExceptionPort_ = client.SetHandlerMachPort(std::move(sendRight)); + DCHECK(didSetExceptionPort_); +} + - (void)deliverNotification:(NSDictionary*)notificationData { + DCHECK(didSetExceptionPort_); + base::scoped_nsobject<NotificationBuilder> builder( [[NotificationBuilder alloc] initWithDictionary:notificationData]); @@ -34,6 +54,8 @@ - (void)closeNotificationWithId:(NSString*)notificationId withProfileId:(NSString*)profileId { + DCHECK(didSetExceptionPort_); + NSUserNotificationCenter* notificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter]; for (NSUserNotification* candidate in @@ -54,6 +76,8 @@ } - (void)closeAllNotifications { + DCHECK(didSetExceptionPort_); + [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications]; [transactionHandler_ closeTransactionIfNeeded];
diff --git a/chrome/browser/ui/cocoa/notifications/notification_delivery.h b/chrome/browser/ui/cocoa/notifications/notification_delivery.h index 8670956..b575bb38 100644 --- a/chrome/browser/ui/cocoa/notifications/notification_delivery.h +++ b/chrome/browser/ui/cocoa/notifications/notification_delivery.h
@@ -7,12 +7,17 @@ #import <Foundation/Foundation.h> +#import "chrome/browser/ui/cocoa/notifications/xpc_mach_port.h" + // Collection of protocols used for XPC communication between chrome // and the alert notification xpc service. // Protocol for the XPC notification service. @protocol NotificationDelivery +// Sets the Mach exception handler port to use for the XPCService. +- (void)setMachExceptionPort:(CrXPCMachPort*)port; + // |notificationData| is generated using a NofiticationBuilder object. - (void)deliverNotification:(NSDictionary*)notificationData; @@ -22,6 +27,7 @@ // Closes all the alerts being displayed. - (void)closeAllNotifications; + @end // Response protocol for the XPC notification service to notify Chrome of
diff --git a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm index 1a648adf..2a7d182 100644 --- a/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm +++ b/chrome/browser/ui/cocoa/notifications/notification_service_delegate.mm
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import <AppKit/AppKit.h> - #import "chrome/browser/ui/cocoa/notifications/notification_service_delegate.h" +#import <AppKit/AppKit.h> + #include "base/mac/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/notifications/alert_notification_service.h" #import "chrome/browser/ui/cocoa/notifications/notification_delivery.h" @@ -57,7 +57,7 @@ return YES; } -// NSUserNotification center delegate +// NSUserNotificationCenterDelegate: - (void)userNotificationCenter:(NSUserNotificationCenter*)center didActivateNotification:(NSUserNotification*)notification { NSDictionary* response = @@ -65,7 +65,7 @@ [[connection_ remoteObjectProxy] notificationClick:response]; } -// _NSUserNotificationCenterDelegatePrivate +// _NSUserNotificationCenterDelegatePrivate: - (void)userNotificationCenter:(NSUserNotificationCenter*)center didDismissAlert:(NSUserNotification*)notification { NSDictionary* response =
diff --git a/chrome/browser/ui/cocoa/notifications/xpc_mach_port.h b/chrome/browser/ui/cocoa/notifications/xpc_mach_port.h new file mode 100644 index 0000000..cdf4041 --- /dev/null +++ b/chrome/browser/ui/cocoa/notifications/xpc_mach_port.h
@@ -0,0 +1,36 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_XPC_MACH_PORT_H_ +#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_XPC_MACH_PORT_H_ + +#import <Foundation/Foundation.h> + +#include "base/mac/scoped_mach_port.h" + +// An XPC transit type for Mach send rights. While this class conforms to +// NSSecureCoding, it is only valid to use the NSCoding methods for XPC. +// +// The public XPC APIs do not proivde any way to transfer Mach ports. Using the +// C-based API, the functions for setting/creating an XPC Mach port object can +// simply be forward-declared. But the Foundation API does not provide any way +// to pass a Mach port as part of a message. The OS_xpc_object Obj-C types +// do not conform to NSSecureCoding either, so they cannot be used to transport +// ports via the Foundation-level API. +// +// Instead, this class encodes Mach port OOL data using the private +// NSXPCEncoder and NSXPCDecoder APIs. These APIs expose methods by which +// xpc_objct_t's (and their OS_object-bridged-siblings) can be encoded into a +// Foundation-level XPC message. +@interface CrXPCMachPort : NSObject<NSSecureCoding> + +// Creates a new transit Mach port by taking ownership of the |sendRight|. +- (instancetype)initWithMachSendRight:(base::mac::ScopedMachSendRight)sendRight; + +// Relinquishes ownership of the Mach port to the caller. +- (base::mac::ScopedMachSendRight)takeRight; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_XPC_MACH_PORT_H_
diff --git a/chrome/browser/ui/cocoa/notifications/xpc_mach_port.mm b/chrome/browser/ui/cocoa/notifications/xpc_mach_port.mm new file mode 100644 index 0000000..aa8cfba --- /dev/null +++ b/chrome/browser/ui/cocoa/notifications/xpc_mach_port.mm
@@ -0,0 +1,80 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/notifications/xpc_mach_port.h" + +#include "base/logging.h" +#include "base/mac/scoped_nsobject.h" + +@class OS_xpc_mach_send; + +extern "C" { + +OS_xpc_mach_send* xpc_mach_send_create(mach_port_t); +mach_port_t xpc_mach_send_copy_right(OS_xpc_mach_send*); + +} // extern "C" + +// Give the compiler declarations for the NSXPCCoder methods. +@protocol ForwardDeclareXPCCoder +- (void)encodeXPCObject:(id)object forKey:(id)key; +- (id)decodeXPCObjectForKey:(id)key; +@end + +namespace { + +NSString* const kCrSendRight = @"org.chromium.xpc.MachSendRight"; + +} // namespace + +@implementation CrXPCMachPort { + base::mac::ScopedMachSendRight port_; +} + +- (instancetype)initWithMachSendRight: + (base::mac::ScopedMachSendRight)sendRight { + if ((self = [super init])) { + DCHECK(sendRight.is_valid()); + port_ = std::move(sendRight); + } + return self; +} + +- (base::mac::ScopedMachSendRight)takeRight { + return std::move(port_); +} + +// NSCoding: +- (instancetype)initWithCoder:(NSCoder*)coder { + DCHECK([coder isKindOfClass:NSClassFromString(@"NSXPCDecoder")]); + if ((self = [super init])) { + id coderAsId = coder; + + OS_xpc_mach_send* xpcObject = + [coderAsId decodeXPCObjectForKey:kCrSendRight]; + if (!xpcObject) + return nil; + + port_.reset(xpc_mach_send_copy_right(xpcObject)); + } + return self; +} + +- (void)encodeWithCoder:(NSCoder*)coder { + DCHECK([coder isKindOfClass:NSClassFromString(@"NSXPCEncoder")]); + DCHECK(port_.is_valid()); + + id coderAsId = coder; + + base::scoped_nsobject<OS_xpc_mach_send> xpcObject( + xpc_mach_send_create(port_.get())); + [coderAsId encodeXPCObject:xpcObject forKey:kCrSendRight]; +} + +// NSSecureCoding: ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end
diff --git a/chrome/browser/ui/cocoa/website_settings/OWNERS b/chrome/browser/ui/cocoa/permission_bubble/OWNERS similarity index 100% rename from chrome/browser/ui/cocoa/website_settings/OWNERS rename to chrome/browser/ui/cocoa/permission_bubble/OWNERS
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h b/chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.h similarity index 84% rename from chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h rename to chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.h index 5ce3262..eec1f13f 100644 --- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h +++ b/chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_COCOA_H_ -#define CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_COCOA_H_ +#ifndef CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_COCOA_H_ #import <Cocoa/Cocoa.h> @@ -42,4 +42,4 @@ DISALLOW_COPY_AND_ASSIGN(ChooserBubbleUiCocoa); }; -#endif // CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_COCOA_H_ +#endif // CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm b/chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.mm similarity index 98% rename from chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm rename to chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.mm index f7e8f1ee5..5950ab6 100644 --- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h" +#import "chrome/browser/ui/cocoa/permission_bubble/chooser_bubble_ui_cocoa.h" #include <stddef.h> @@ -22,7 +22,7 @@ #import "chrome/browser/ui/cocoa/info_bubble_view.h" #import "chrome/browser/ui/cocoa/info_bubble_window.h" #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" +#include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "components/bubble/bubble_controller.h" #include "content/public/browser/native_web_keyboard_event.h" #include "ui/base/cocoa/cocoa_base_utils.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h similarity index 86% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h index e13dadf..a683ad3 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_COCOA_H_ -#define CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_COCOA_H_ +#ifndef CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_COCOA_H_ #import <Foundation/Foundation.h> @@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/cocoa/info_bubble_view.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "content/public/browser/web_contents.h" class Browser; @@ -56,4 +56,4 @@ DISALLOW_COPY_AND_ASSIGN(PermissionBubbleCocoa); }; -#endif // CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_COCOA_H_ +#endif // CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm similarity index 88% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm index fb8f01f..88d5821 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.mm
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" +#include "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" #include "base/memory/ptr_util.h" #import "chrome/browser/ui/cocoa/base_bubble_controller.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h" -#import "chrome/browser/ui/website_settings/permission_prompt.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h" +#import "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "content/public/browser/web_contents.h" #import "ui/base/cocoa/nsview_additions.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa_browser_test.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm similarity index 93% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa_browser_test.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm index 663b3f2..de7d740 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa_browser_test.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm
@@ -4,11 +4,11 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands_mac.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" +#include "chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/website_settings/permission_bubble_browser_test_util.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #import "testing/gtest_mac.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa_interactive_uitest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm similarity index 100% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa_interactive_uitest.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h similarity index 87% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h index 25e3da5b..5dec145 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_CONTROLLER_H_ -#define CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_CONTROLLER_H_ +#ifndef CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_CONTROLLER_H_ +#define CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_CONTROLLER_H_ #import <Cocoa/Cocoa.h> #include "base/mac/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/omnibox_decoration_bubble_controller.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "ui/base/models/simple_menu_model.h" class Browser; @@ -65,4 +65,4 @@ @end -#endif // CHROME_BROWSER_UI_COCOA_WEBSITE_SETTINGS_PERMISSION_BUBBLE_CONTROLLER_H_ +#endif // CHROME_BROWSER_UI_COCOA_PERMISSION_BUBBLE_PERMISSION_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm similarity index 98% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm index 5872ab0..3fff34a 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h" #include <algorithm> @@ -25,12 +25,12 @@ #include "chrome/browser/ui/cocoa/page_info/permission_selector_button.h" #include "chrome/browser/ui/cocoa/page_info/split_block_button.h" #include "chrome/browser/ui/cocoa/page_info/website_settings_utils_cocoa.h" -#include "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" +#include "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/page_info/permission_menu_model.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm similarity index 98% rename from chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm index fb360b4..4ff4a76 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h" #include <Carbon/Carbon.h> @@ -18,9 +18,9 @@ #include "chrome/browser/ui/cocoa/browser_window_controller.h" #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/page_info/split_block_button.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" #import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h" #include "chrome/browser/ui/cocoa/test/run_loop_testing.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_prompt_impl_views_mac.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_prompt_impl_views_mac.mm similarity index 86% rename from chrome/browser/ui/cocoa/website_settings/permission_prompt_impl_views_mac.mm rename to chrome/browser/ui/cocoa/permission_bubble/permission_prompt_impl_views_mac.mm index cfd0f53..79c8a95 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_prompt_impl_views_mac.mm +++ b/chrome/browser/ui/cocoa/permission_bubble/permission_prompt_impl_views_mac.mm
@@ -8,9 +8,9 @@ #include "chrome/browser/ui/browser_window.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h" -#import "chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.h" -#include "chrome/browser/ui/views/website_settings/permission_prompt_impl.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h" +#import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.h" +#include "chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h" #import "ui/base/cocoa/cocoa_base_utils.h" #include "ui/base/material_design/material_design_controller.h" #import "ui/gfx/mac/coordinate_conversion.h"
diff --git a/chrome/browser/ui/location_bar/location_bar_util.cc b/chrome/browser/ui/location_bar/location_bar_util.cc deleted file mode 100644 index 38188593..0000000 --- a/chrome/browser/ui/location_bar/location_bar_util.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/location_bar/location_bar_util.h" - -#include <stddef.h> - -#include "base/i18n/rtl.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/gfx/text_elider.h" - -namespace location_bar_util { - -base::string16 CalculateMinString(const base::string16& description) { - // Chop at the first '.' or whitespace. - const size_t chop_index = description.find_first_of( - base::kWhitespaceUTF16 + base::ASCIIToUTF16(".")); - base::string16 min_string((chop_index == base::string16::npos) ? - gfx::TruncateString(description, 3, gfx::WORD_BREAK) : - description.substr(0, chop_index)); - base::i18n::AdjustStringForLocaleDirection(&min_string); - return min_string; -} - -} // namespace location_bar_util
diff --git a/chrome/browser/ui/location_bar/location_bar_util.h b/chrome/browser/ui/location_bar/location_bar_util.h deleted file mode 100644 index a4083697..0000000 --- a/chrome/browser/ui/location_bar/location_bar_util.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_UTIL_H_ -#define CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_UTIL_H_ - -#include "base/strings/string16.h" - -namespace location_bar_util { - -// Build a short string to use in keyword-search when the field isn't very big. -base::string16 CalculateMinString(const base::string16& description); - -} // namespace location_bar_util - -#endif // CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_UTIL_H_
diff --git a/chrome/browser/ui/website_settings/OWNERS b/chrome/browser/ui/permission_bubble/OWNERS similarity index 100% rename from chrome/browser/ui/website_settings/OWNERS rename to chrome/browser/ui/permission_bubble/OWNERS
diff --git a/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc b/chrome/browser/ui/permission_bubble/chooser_bubble_delegate.cc similarity index 92% rename from chrome/browser/ui/website_settings/chooser_bubble_delegate.cc rename to chrome/browser/ui/permission_bubble/chooser_bubble_delegate.cc index 1792db2..121eb179 100644 --- a/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc +++ b/chrome/browser/ui/permission_bubble/chooser_bubble_delegate.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" +#include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "chrome/browser/chooser_controller/chooser_controller.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h b/chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h similarity index 86% rename from chrome/browser/ui/website_settings/chooser_bubble_delegate.h rename to chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h index e521b54..134cda0 100644 --- a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h +++ b/chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBSITE_SETTINGS_CHOOSER_BUBBLE_DELEGATE_H_ -#define CHROME_BROWSER_UI_WEBSITE_SETTINGS_CHOOSER_BUBBLE_DELEGATE_H_ +#ifndef CHROME_BROWSER_UI_PERMISSION_BUBBLE_CHOOSER_BUBBLE_DELEGATE_H_ +#define CHROME_BROWSER_UI_PERMISSION_BUBBLE_CHOOSER_BUBBLE_DELEGATE_H_ #include "base/macros.h" #include "components/bubble/bubble_delegate.h" @@ -42,4 +42,4 @@ DISALLOW_COPY_AND_ASSIGN(ChooserBubbleDelegate); }; -#endif // CHROME_BROWSER_UI_WEBSITE_SETTINGS_CHOOSER_BUBBLE_DELEGATE_H_ +#endif // CHROME_BROWSER_UI_PERMISSION_BUBBLE_CHOOSER_BUBBLE_DELEGATE_H_
diff --git a/chrome/browser/ui/website_settings/mock_permission_prompt.cc b/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc similarity index 90% rename from chrome/browser/ui/website_settings/mock_permission_prompt.cc rename to chrome/browser/ui/permission_bubble/mock_permission_prompt.cc index d0e9cb0..48dd339 100644 --- a/chrome/browser/ui/website_settings/mock_permission_prompt.cc +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/website_settings/mock_permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt.h" #include "base/bind.h" #include "base/run_loop.h" #include "chrome/browser/permissions/permission_request_manager.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" MockPermissionPrompt::~MockPermissionPrompt() { Hide();
diff --git a/chrome/browser/ui/website_settings/mock_permission_prompt.h b/chrome/browser/ui/permission_bubble/mock_permission_prompt.h similarity index 81% rename from chrome/browser/ui/website_settings/mock_permission_prompt.h rename to chrome/browser/ui/permission_bubble/mock_permission_prompt.h index a3a1d01..efe690fe 100644 --- a/chrome/browser/ui/website_settings/mock_permission_prompt.h +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt.h
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_H_ -#define CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_H_ +#ifndef CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_H_ +#define CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_H_ -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" class MockPermissionPromptFactory; class PermissionRequestManager; @@ -40,4 +40,4 @@ bool is_visible_; }; -#endif // CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_H_ +#endif // CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_H_
diff --git a/chrome/browser/ui/website_settings/mock_permission_prompt_factory.cc b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc similarity index 94% rename from chrome/browser/ui/website_settings/mock_permission_prompt_factory.cc rename to chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc index ddf28bfc..11a96b4 100644 --- a/chrome/browser/ui/website_settings/mock_permission_prompt_factory.cc +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/website_settings/mock_permission_prompt_factory.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "chrome/browser/permissions/permission_request_manager.h" -#include "chrome/browser/ui/website_settings/mock_permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt.h" #include "content/public/browser/web_contents.h" MockPermissionPromptFactory::MockPermissionPromptFactory(
diff --git a/chrome/browser/ui/website_settings/mock_permission_prompt_factory.h b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h similarity index 90% rename from chrome/browser/ui/website_settings/mock_permission_prompt_factory.h rename to chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h index 2170345..ad02121 100644 --- a/chrome/browser/ui/website_settings/mock_permission_prompt_factory.h +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_FACTORY_H_ -#define CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_FACTORY_H_ +#ifndef CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_FACTORY_H_ +#define CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_FACTORY_H_ #include <memory> #include <vector> @@ -82,4 +82,4 @@ DISALLOW_COPY_AND_ASSIGN(MockPermissionPromptFactory); }; -#endif // CHROME_BROWSER_UI_WEBSITE_SETTINGS_MOCK_PERMISSION_PROMPT_FACTORY_H_ +#endif // CHROME_BROWSER_UI_PERMISSION_BUBBLE_MOCK_PERMISSION_PROMPT_FACTORY_H_
diff --git a/chrome/browser/ui/website_settings/permission_bubble_browser_test_util.cc b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc similarity index 96% rename from chrome/browser/ui/website_settings/permission_bubble_browser_test_util.cc rename to chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc index de85749..fe6b7a0 100644 --- a/chrome/browser/ui/website_settings/permission_bubble_browser_test_util.cc +++ b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/website_settings/permission_bubble_browser_test_util.h" +#include "chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h" #include "base/command_line.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/ui/website_settings/permission_bubble_browser_test_util.h b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h similarity index 85% rename from chrome/browser/ui/website_settings/permission_bubble_browser_test_util.h rename to chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h index 752bbc6..66a8295 100644 --- a/chrome/browser/ui/website_settings/permission_bubble_browser_test_util.h +++ b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_ -#define CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_ +#ifndef CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_ +#define CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_ #include <memory> #include <vector> #include "base/macros.h" #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" namespace base { class CommandLine; @@ -68,4 +68,4 @@ DISALLOW_COPY_AND_ASSIGN(PermissionBubbleKioskBrowserTest); }; -#endif // CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_ +#endif // CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_BUBBLE_BROWSER_TEST_UTIL_H_
diff --git a/chrome/browser/ui/website_settings/permission_prompt.h b/chrome/browser/ui/permission_bubble/permission_prompt.h similarity index 92% rename from chrome/browser/ui/website_settings/permission_prompt.h rename to chrome/browser/ui/permission_bubble/permission_prompt.h index 4b7dd15e..ec5b65e 100644 --- a/chrome/browser/ui/website_settings/permission_prompt.h +++ b/chrome/browser/ui/permission_bubble/permission_prompt.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_PROMPT_H_ -#define CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_PROMPT_H_ +#ifndef CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_PROMPT_H_ +#define CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_PROMPT_H_ #include <memory> #include <vector> @@ -76,4 +76,4 @@ virtual gfx::NativeWindow GetNativeWindow() = 0; }; -#endif // CHROME_BROWSER_UI_WEBSITE_SETTINGS_PERMISSION_PROMPT_H_ +#endif // CHROME_BROWSER_UI_PERMISSION_BUBBLE_PERMISSION_PROMPT_H_
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index 4a1ee58..7dca4b0 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -117,8 +117,8 @@ // the label has zero size it doesn't actually matter what we compute its X // value to be, since it won't be visible. const int label_x = image_->bounds().right() + GetInternalSpacing(); - const int label_width = - std::max(0, width() - label_x - bubble_trailing_padding); + const int label_width = std::max( + 0, width() - label_x - bubble_trailing_padding - kSpaceBesideSeparator); label_->SetBounds(label_x, 0, label_width, height()); } @@ -229,13 +229,7 @@ gfx::Rect bounds(label_->bounds()); const int kSeparatorHeight = 16; bounds.Inset(0, (bounds.height() - kSeparatorHeight) / 2); - - // Draw the 1 px separator. - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - // Keep the separator aligned on a pixel center. - const gfx::RectF pixel_aligned_bounds = - gfx::ScaleRect(gfx::RectF(bounds), scale) - gfx::Vector2dF(0.5f, 0); - canvas->DrawLine(pixel_aligned_bounds.top_right(), - pixel_aligned_bounds.bottom_right(), separator_color); + bounds.set_width(bounds.width() + kSpaceBesideSeparator); + canvas->Draw1pxLine(gfx::PointF(bounds.top_right()), + gfx::PointF(bounds.bottom_right()), separator_color); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index afdd605..0887f380b 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -473,12 +473,15 @@ // hits ctrl-d). const int vertical_padding = GetTotalVerticalPadding(); const int location_height = std::max(height() - (vertical_padding * 2), 0); + // The largest fraction of the omnibox that can be taken by the EV or search + // label/chip. + const double kLeadingDecorationMaxFraction = 0.5; location_icon_view_->SetLabel(base::string16()); if (ShouldShowKeywordBubble()) { - leading_decorations.AddDecoration(vertical_padding, location_height, true, - 0, item_padding, item_padding, - selected_keyword_view_); + leading_decorations.AddDecoration( + vertical_padding, location_height, false, kLeadingDecorationMaxFraction, + item_padding, item_padding, selected_keyword_view_); if (selected_keyword_view_->keyword() != keyword) { selected_keyword_view_->SetKeyword(keyword); const TemplateURL* template_url = @@ -495,11 +498,9 @@ } } else if (ShouldShowLocationIconText()) { location_icon_view_->SetLabel(GetLocationIconText()); - // The largest fraction of the omnibox that can be taken by the EV bubble. - const double kMaxBubbleFraction = 0.5; - leading_decorations.AddDecoration(vertical_padding, location_height, false, - kMaxBubbleFraction, item_padding, - item_padding, location_icon_view_); + leading_decorations.AddDecoration( + vertical_padding, location_height, false, kLeadingDecorationMaxFraction, + item_padding, item_padding, location_icon_view_); } else { leading_decorations.AddDecoration(vertical_padding, location_height, location_icon_view_);
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc index 981a122b..e2e3280a 100644 --- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc +++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -7,7 +7,6 @@ #include "base/logging.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" -#include "chrome/browser/ui/location_bar/location_bar_util.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/grit/generated_resources.h" #include "components/search_engines/template_url_service.h" @@ -26,6 +25,7 @@ full_label_.SetVisible(false); partial_label_.SetFontList(font_list); partial_label_.SetVisible(false); + label()->SetElideBehavior(gfx::FADE_TAIL); } SelectedKeywordView::~SelectedKeywordView() { @@ -50,12 +50,18 @@ gfx::Size SelectedKeywordView::GetMinimumSize() const { // Height will be ignored by the LocationBarView. - return GetSizeForLabelWidth(partial_label_.GetMinimumSize().width()); + return GetSizeForLabelWidth(0); } void SelectedKeywordView::Layout() { - SetLabel(((width() == GetPreferredSize().width()) ? - full_label_ : partial_label_).text()); + // Keep showing the full label as long as there's more than enough width for + // the partial label. Otherwise there will be empty space displayed next to + // the partial label. + bool use_full_label = + width() > + GetSizeForLabelWidth(partial_label_.GetPreferredSize().width()).width(); + SetLabel(use_full_label ? full_label_.text() : partial_label_.text()); + IconLabelBubbleView::Layout(); } @@ -78,14 +84,7 @@ : l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT_MD, short_name); full_label_.SetText(full_name); - const base::string16 min_string( - location_bar_util::CalculateMinString(short_name)); - const base::string16 partial_name = - is_extension_keyword - ? min_string - : l10n_util::GetStringFUTF16(IDS_OMNIBOX_KEYWORD_TEXT_MD, min_string); - partial_label_.SetText(min_string.empty() ? - full_label_.text() : partial_name); + partial_label_.SetText(short_name); // Update the label now so ShouldShowLabel() works correctly when the parent // class is calculating the preferred size. It will be updated again in
diff --git a/chrome/browser/ui/views/website_settings/OWNERS b/chrome/browser/ui/views/permission_bubble/OWNERS similarity index 100% rename from chrome/browser/ui/views/website_settings/OWNERS rename to chrome/browser/ui/views/permission_bubble/OWNERS
diff --git a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.cc similarity index 97% rename from chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc rename to chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.cc index 9addbb1..ef305f7 100644 --- a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc +++ b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h" +#include "chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.h" #include <stddef.h> @@ -14,13 +14,13 @@ #include "chrome/browser/chooser_controller/chooser_controller.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "chrome/browser/ui/views/device_chooser_content_view.h" #include "chrome/browser/ui/views/exclusive_access_bubble_views.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/browser/ui/views/location_bar/location_icon_view.h" -#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" #include "components/bubble/bubble_controller.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/link.h"
diff --git a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.h similarity index 85% rename from chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h rename to chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.h index 596dbd3..e2385a0a 100644 --- a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h +++ b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_VIEW_H_ -#define CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_VIEW_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_VIEW_H_ #include <memory> @@ -46,4 +46,4 @@ DISALLOW_COPY_AND_ASSIGN(ChooserBubbleUiView); }; -#endif // CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_CHOOSER_BUBBLE_UI_VIEW_H_ +#endif // CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_CHOOSER_BUBBLE_UI_VIEW_H_
diff --git a/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc similarity index 99% rename from chrome/browser/ui/views/website_settings/permission_prompt_impl.cc rename to chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc index 582c3ba..47835f5 100644 --- a/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/website_settings/permission_prompt_impl.h" +#include "chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h" #include <stddef.h>
diff --git a/chrome/browser/ui/views/website_settings/permission_prompt_impl.h b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h similarity index 85% rename from chrome/browser/ui/views/website_settings/permission_prompt_impl.h rename to chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h index 0825619..e84f22d 100644 --- a/chrome/browser/ui/views/website_settings/permission_prompt_impl.h +++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_PERMISSION_PROMPT_IMPL_H_ -#define CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_PERMISSION_PROMPT_IMPL_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_PERMISSION_PROMPT_IMPL_H_ +#define CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_PERMISSION_PROMPT_IMPL_H_ #include <memory> #include <string> #include "base/compiler_specific.h" #include "base/macros.h" -#include "chrome/browser/ui/website_settings/permission_prompt.h" +#include "chrome/browser/ui/permission_bubble/permission_prompt.h" #include "ui/gfx/geometry/point.h" #include "ui/views/bubble/bubble_border.h" @@ -64,4 +64,4 @@ DISALLOW_COPY_AND_ASSIGN(PermissionPromptImpl); }; -#endif // CHROME_BROWSER_UI_VIEWS_WEBSITE_SETTINGS_PERMISSION_PROMPT_IMPL_H_ +#endif // CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_PERMISSION_PROMPT_IMPL_H_
diff --git a/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl_views.cc similarity index 96% rename from chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc rename to chrome/browser/ui/views/permission_bubble/permission_prompt_impl_views.cc index cf1117e..1b688ec 100644 --- a/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl_views.cc
@@ -11,7 +11,7 @@ #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "chrome/browser/ui/views/location_bar/location_icon_view.h" -#include "chrome/browser/ui/views/website_settings/permission_prompt_impl.h" +#include "chrome/browser/ui/views/permission_bubble/permission_prompt_impl.h" #include "content/public/browser/web_contents.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/vector2d.h"
diff --git a/chrome/browser/usb/web_usb_chooser_service.cc b/chrome/browser/usb/web_usb_chooser_service.cc index e7efb5e..7ad5384 100644 --- a/chrome/browser/usb/web_usb_chooser_service.cc +++ b/chrome/browser/usb/web_usb_chooser_service.cc
@@ -8,7 +8,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_bubble_manager.h" -#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" +#include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "chrome/browser/usb/usb_chooser_controller.h" #include "components/bubble/bubble_controller.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index d480ff03..3734f21e 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc
@@ -160,8 +160,6 @@ const base::FilePath::CharType kPreferencesFilename[] = FPL("Preferences"); const base::FilePath::CharType kPreviewsOptOutDBFilename[] = FPL("previews_opt_out.db"); -const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[] = - FPL("Protected Preferences"); const base::FilePath::CharType kReadmeFilename[] = FPL("README"); const base::FilePath::CharType kSecurePreferencesFilename[] = FPL("Secure Preferences");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index d738b8e..2e39ef21 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h
@@ -61,7 +61,6 @@ extern const base::FilePath::CharType kOfflinePageRequestQueueDirname[]; extern const base::FilePath::CharType kPreferencesFilename[]; extern const base::FilePath::CharType kPreviewsOptOutDBFilename[]; -extern const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[]; extern const base::FilePath::CharType kReadmeFilename[]; extern const base::FilePath::CharType kSecurePreferencesFilename[]; extern const base::FilePath::CharType kServiceStateFileName[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 8f42c09..7c1d1be 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -388,7 +388,7 @@ "../browser/ui/browser_focus_uitest.cc", "../browser/ui/cocoa/apps/app_shim_menu_controller_mac_interactive_uitest.mm", "../browser/ui/cocoa/apps/quit_with_apps_controller_mac_interactive_uitest.mm", - "../browser/ui/cocoa/website_settings/permission_bubble_cocoa_interactive_uitest.mm", + "../browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm", "../browser/ui/exclusive_access/flash_fullscreen_interactive_browsertest.cc", "../browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc", "../browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc", @@ -1775,6 +1775,12 @@ "../browser/ui/location_bar/location_bar_browsertest.cc", "../browser/ui/login/login_handler_browsertest.cc", "../browser/ui/native_window_tracker_browsertest.cc", + "../browser/ui/permission_bubble/mock_permission_prompt.cc", + "../browser/ui/permission_bubble/mock_permission_prompt.h", + "../browser/ui/permission_bubble/mock_permission_prompt_factory.cc", + "../browser/ui/permission_bubble/mock_permission_prompt_factory.h", + "../browser/ui/permission_bubble/permission_bubble_browser_test_util.cc", + "../browser/ui/permission_bubble/permission_bubble_browser_test_util.h", "../browser/ui/passwords/manage_passwords_test.cc", "../browser/ui/prefs/prefs_tab_helper_browsertest.cc", "../browser/ui/profile_error_browsertest.cc", @@ -1798,12 +1804,6 @@ "../browser/ui/toolbar/mock_component_toolbar_actions_factory.h", "../browser/ui/update_chrome_dialog_browsertest.cc", "../browser/ui/views/hung_renderer_view_browsertest.cc", - "../browser/ui/website_settings/mock_permission_prompt.cc", - "../browser/ui/website_settings/mock_permission_prompt.h", - "../browser/ui/website_settings/mock_permission_prompt_factory.cc", - "../browser/ui/website_settings/mock_permission_prompt_factory.h", - "../browser/ui/website_settings/permission_bubble_browser_test_util.cc", - "../browser/ui/website_settings/permission_bubble_browser_test_util.h", "../browser/ui/webui/bidi_checker_web_ui_test.cc", "../browser/ui/webui/bidi_checker_web_ui_test.h", "../browser/ui/webui/bookmarks_ui_browsertest.cc", @@ -2553,13 +2553,13 @@ "../browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm", "../browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm", "../browser/ui/cocoa/passwords/passwords_bubble_browsertest.mm", + "../browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_browser_test.mm", "../browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm", "../browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_browsertest.mm", "../browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm", "../browser/ui/cocoa/task_manager_mac_browsertest.mm", "../browser/ui/cocoa/view_id_util_browsertest.mm", "../browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm", - "../browser/ui/cocoa/website_settings/permission_bubble_cocoa_browser_test.mm", ] } } @@ -3252,6 +3252,7 @@ "../browser/page_load_metrics/observers/document_write_page_load_metrics_observer_unittest.cc", "../browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc", "../browser/page_load_metrics/observers/google_captcha_observer_unittest.cc", + "../browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc", "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc", "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h", "../browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc", @@ -3270,7 +3271,6 @@ "../browser/password_manager/password_store_x_unittest.cc", "../browser/password_manager/simple_password_store_mac_unittest.cc", "../browser/permissions/chooser_context_base_unittest.cc", - "../browser/permissions/delegation_tracker_unittest.cc", "../browser/permissions/permission_context_base_unittest.cc", "../browser/permissions/permission_decision_auto_blocker_unittest.cc", "../browser/permissions/permission_manager_unittest.cc", @@ -3373,6 +3373,10 @@ "../browser/ui/find_bar/find_backend_unittest.cc", "../browser/ui/login/login_handler_unittest.cc", "../browser/ui/page_info/website_settings_unittest.cc", + "../browser/ui/permission_bubble/mock_permission_prompt.cc", + "../browser/ui/permission_bubble/mock_permission_prompt.h", + "../browser/ui/permission_bubble/mock_permission_prompt_factory.cc", + "../browser/ui/permission_bubble/mock_permission_prompt_factory.h", "../browser/ui/passwords/manage_passwords_state_unittest.cc", "../browser/ui/passwords/manage_passwords_view_utils_unittest.cc", "../browser/ui/passwords/password_manager_presenter_unittest.cc", @@ -3381,10 +3385,6 @@ "../browser/ui/sync/sync_promo_ui_unittest.cc", "../browser/ui/tests/ui_gfx_image_unittest.cc", "../browser/ui/tests/ui_gfx_image_unittest.mm", - "../browser/ui/website_settings/mock_permission_prompt.cc", - "../browser/ui/website_settings/mock_permission_prompt.h", - "../browser/ui/website_settings/mock_permission_prompt_factory.cc", - "../browser/ui/website_settings/mock_permission_prompt_factory.h", "../browser/ui/webui/browsing_history_handler_unittest.cc", "../browser/ui/webui/fileicon_source_unittest.cc", "../browser/ui/webui/local_state/local_state_ui_unittest.cc", @@ -4358,6 +4358,7 @@ "../browser/printing/print_preview_dialog_controller_unittest.cc", "../browser/printing/print_preview_test.cc", "../browser/printing/print_preview_test.h", + "../browser/printing/print_view_manager_unittest.cc", "../browser/ui/webui/print_preview/extension_printer_handler_unittest.cc", "../browser/ui/webui/print_preview/print_preview_ui_unittest.cc", "../browser/ui/webui/print_preview/printer_capabilities_unittest.cc", @@ -4663,6 +4664,7 @@ "../browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm", "../browser/ui/cocoa/passwords/signin_promo_view_controller_unittest.mm", "../browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm", + "../browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm", "../browser/ui/cocoa/profiles/avatar_button_controller_unittest.mm", "../browser/ui/cocoa/profiles/avatar_button_unittest.mm", "../browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm", @@ -4698,7 +4700,6 @@ "../browser/ui/cocoa/vertical_gradient_view_unittest.mm", "../browser/ui/cocoa/view_resizer_pong.h", "../browser/ui/cocoa/view_resizer_pong.mm", - "../browser/ui/cocoa/website_settings/permission_bubble_controller_unittest.mm", "../browser/ui/cocoa/window_size_autosaver_unittest.mm", ] }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 799137f..cd41f3e 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -74,6 +74,10 @@ # https://bugs.chromium.org/p/chromedriver/issues/detail?id=992 'ChromeDownloadDirTest.testDownloadDirectoryOverridesExistingPreferences', ] +_VERSION_SPECIFIC_FILTER['58'] = [ + # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1673 + 'ChromeDriverPageLoadTimeoutTest.testPageLoadTimeoutCrossDomain', +] _VERSION_SPECIFIC_FILTER['57'] = [ # https://bugs.chromium.org/p/chromedriver/issues/detail?id=992 'ChromeDownloadDirTest.testDownloadDirectoryOverridesExistingPreferences',
diff --git a/chrome/test/data/extensions/platform_apps/web_view/ime/guest.html b/chrome/test/data/extensions/platform_apps/web_view/ime/guest.html new file mode 100644 index 0000000..4253415 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/ime/guest.html
@@ -0,0 +1,44 @@ +<!doctype html> +<!-- + * Copyright 2017 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<html> +<header> + <style> + #editbox { + position: fixed; + width: 200px; + height: 100px; + } + </style> +</header> +<body> + <input id="editbox"/> + <script> + var parentWindow = null; + var input = null; + + window.addEventListener('load', function() { + input = document.getElementById('editbox'); + input.addEventListener('focus', function() { + input.value = 'A B X D'; + parentWindow.postMessage({type: 'focus'}, '*'); + }); + }); + + window.addEventListener('message', function(e) { + parentWindow = e.source; + parentWindow.postMessage({type: 'init'}, '*'); + }); + + window.addEventListener('input', function(e) { + parentWindow.postMessage({ + type: 'input', + value: input.innerText}, '*'); + }); + + </script> +</body> +</html> \ No newline at end of file
diff --git a/chrome/test/data/extensions/platform_apps/web_view/ime/main.html b/chrome/test/data/extensions/platform_apps/web_view/ime/main.html new file mode 100644 index 0000000..39006f9 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/ime/main.html
@@ -0,0 +1,21 @@ +<!doctype html> +<!-- + * Copyright 2017 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<html> +<header> +<style> + #webview-tag-container { + position: fixed; + width: 100%; + height: 100%; + } +</style> +</header> +<body> + <div id="webview-tag-container"></div> + <script src="main.js"></script> +</body> +</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/ime/main.js b/chrome/test/data/extensions/platform_apps/web_view/ime/main.js new file mode 100644 index 0000000..0464b2f --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/ime/main.js
@@ -0,0 +1,31 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +window.addEventListener('load', function() { + window.webview = document.createElement('webview'); + document.querySelector('#webview-tag-container').appendChild(webview); + + webview.style.width = "100%"; + webview.style.height = "100%"; + webview.addEventListener('loadstop', function() { + webview.contentWindow.postMessage({}, '*'); + }); + + chrome.test.getConfig(function(config) { + var url = 'http://localhost:' + config.testServer.port + + '/extensions/platform_apps/web_view/ime/guest.html'; + webview.src = url; + }); +}); + +window.addEventListener('message', function(e) { + if (e.data.type === 'init') { + chrome.test.sendMessage('WebViewImeTest.Launched'); + } else if (e.data.type === 'focus') { + chrome.test.sendMessage('WebViewImeTest.InputFocused') + } else if (e.data.type === 'input') { + chrome.test.sendMessage('WebViewImetest.InputReceived') + } +}); +
diff --git a/chrome/test/data/extensions/platform_apps/web_view/ime/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/ime/manifest.json new file mode 100644 index 0000000..bcf75c5 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/ime/manifest.json
@@ -0,0 +1,12 @@ +{ + "name": "<webview> IME tests.", + "version": "1", + "permissions": [ + "webview" + ], + "app": { + "background": { + "scripts": ["test.js"] + } + } +}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/ime/test.js b/chrome/test/data/extensions/platform_apps/web_view/ime/test.js new file mode 100644 index 0000000..40a8908 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/ime/test.js
@@ -0,0 +1,7 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('main.html', {}, function () {}); +});
diff --git a/chrome/test/data/webui/md_bookmarks/reducers_test.js b/chrome/test/data/webui/md_bookmarks/reducers_test.js index ba605475..02a8b93f 100644 --- a/chrome/test/data/webui/md_bookmarks/reducers_test.js +++ b/chrome/test/data/webui/md_bookmarks/reducers_test.js
@@ -82,81 +82,78 @@ suite('closed folder state', function() { var nodes; - // TODO(tsergeant): Remove use of 'initialState' and 'nextState'. - var initialState; + var state; + var action; setup(function() { nodes = testTree(createFolder('1', [ createFolder('2', []), ])); - initialState = {}; + state = {}; }); test('toggle folder open state', function() { - var action = bookmarks.actions.changeFolderOpen('2', false); - var nextState = bookmarks.ClosedFolderState.updateClosedFolders( - initialState, action, nodes); - assertFalse(!!nextState['1']); - assertTrue(nextState['2']); + action = bookmarks.actions.changeFolderOpen('2', false); + state = + bookmarks.ClosedFolderState.updateClosedFolders(state, action, nodes); + assertFalse(!!state['1']); + assertTrue(state['2']); }); test('select folder with closed parent', function() { - var action; - var nextState; // Close '1' action = bookmarks.actions.changeFolderOpen('1', false); - nextState = bookmarks.ClosedFolderState.updateClosedFolders( - initialState, action, nodes); - assertTrue(nextState['1']); - assertFalse(!!nextState['2']); + state = + bookmarks.ClosedFolderState.updateClosedFolders(state, action, nodes); + assertTrue(state['1']); + assertFalse(!!state['2']); // Should re-open when '2' is selected. action = bookmarks.actions.selectFolder('2'); - nextState = bookmarks.ClosedFolderState.updateClosedFolders( - nextState, action, nodes); - assertFalse(!!nextState['1']); + state = + bookmarks.ClosedFolderState.updateClosedFolders(state, action, nodes); + assertFalse(!!state['1']); }); }); suite('selected folder', function() { var nodes; - var initialState; + var state; + var action; setup(function() { nodes = testTree(createFolder('1', [ createFolder('2', []), ])); - initialState = '1'; + state = '1'; }); test('updates from selectFolder action', function() { - var action = bookmarks.actions.selectFolder('2'); - var newState = bookmarks.SelectedFolderState.updateSelectedFolder( - initialState, action, nodes); - assertEquals('2', newState); + action = bookmarks.actions.selectFolder('2'); + state = bookmarks.SelectedFolderState.updateSelectedFolder( + state, action, nodes); + assertEquals('2', state); }); test('updates when parent of selected folder is closed', function() { - var action; - var newState; - action = bookmarks.actions.selectFolder('2'); - newState = bookmarks.SelectedFolderState.updateSelectedFolder( - initialState, action, nodes); + state = bookmarks.SelectedFolderState.updateSelectedFolder( + state, action, nodes); action = bookmarks.actions.changeFolderOpen('1', false); - newState = bookmarks.SelectedFolderState.updateSelectedFolder( - newState, action, nodes); - assertEquals('1', newState); + state = bookmarks.SelectedFolderState.updateSelectedFolder( + state, action, nodes); + assertEquals('1', state); }); }); suite('node state', function() { - var initialState; + var state; + var action; setup(function() { - initialState = testTree( + state = testTree( createFolder( '1', [ @@ -168,37 +165,37 @@ }); test('updates when a node is edited', function() { - var action = bookmarks.actions.editBookmark('2', {title: 'b'}); - var nextState = bookmarks.NodeState.updateNodes(initialState, action); + action = bookmarks.actions.editBookmark('2', {title: 'b'}); + state = bookmarks.NodeState.updateNodes(state, action); - assertEquals('b', nextState['2'].title); - assertEquals('a.com', nextState['2'].url); + assertEquals('b', state['2'].title); + assertEquals('a.com', state['2'].url); action = bookmarks.actions.editBookmark('2', {title: 'c', url: 'c.com'}); - nextState = bookmarks.NodeState.updateNodes(nextState, action); + state = bookmarks.NodeState.updateNodes(state, action); - assertEquals('c', nextState['2'].title); - assertEquals('c.com', nextState['2'].url); + assertEquals('c', state['2'].title); + assertEquals('c.com', state['2'].url); action = bookmarks.actions.editBookmark('4', {title: 'folder'}); - nextState = bookmarks.NodeState.updateNodes(nextState, action); + state = bookmarks.NodeState.updateNodes(state, action); - assertEquals('folder', nextState['4'].title); - assertEquals(undefined, nextState['4'].url); + assertEquals('folder', state['4'].title); + assertEquals(undefined, state['4'].url); // Cannot edit URL of a folder: action = bookmarks.actions.editBookmark('4', {url: 'folder.com'}); - nextState = bookmarks.NodeState.updateNodes(nextState, action); + state = bookmarks.NodeState.updateNodes(state, action); - assertEquals('folder', nextState['4'].title); - assertEquals(undefined, nextState['4'].url); + assertEquals('folder', state['4'].title); + assertEquals(undefined, state['4'].url); }); test('updates when a node is deleted', function() { - var action = bookmarks.actions.removeBookmark('3', '1', 1); - var nextState = bookmarks.NodeState.updateNodes(initialState, action); + action = bookmarks.actions.removeBookmark('3', '1', 1); + state = bookmarks.NodeState.updateNodes(state, action); - assertDeepEquals(['2', '4'], nextState['1'].children); + assertDeepEquals(['2', '4'], state['1'].children); // TODO(tsergeant): Deleted nodes should be removed from the nodes map // entirely.
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index 565e212..9bb396a 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -759,6 +759,11 @@ browsePreload: 'chrome://md-settings/privacy_page/privacy_page.html', /** @override */ + commandLineSwitches: [{ + switchName: 'enable-site-settings', + }], + + /** @override */ extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([ // TODO(dbeam): split these up. 'category_default_setting_tests.js',
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js index 852a35a93..ba0bcf6 100644 --- a/chrome/test/data/webui/settings/site_list_tests.js +++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -650,7 +650,6 @@ setUpCategory(contentType, settings.PermissionValues.ALLOW, prefs); return browserProxy.whenCalled('getExceptionList').then( function(actualContentType) { - testElement.enableSiteSettings_ = true; assertEquals(contentType, actualContentType); // Required for firstItem to be found below. @@ -781,7 +780,6 @@ var resolver = new PromiseResolver(); testElement.async(resolver.resolve); return resolver.promise.then(function() { - testElement.enableSiteSettings_ = true; // All Sites calls getExceptionList for all categories, starting // with Cookies. assertEquals( @@ -825,7 +823,6 @@ var resolver = new PromiseResolver(); testElement.async(resolver.resolve); return resolver.promise.then(function() { - testElement.enableSiteSettings_ = true; // All Sites calls getExceptionList for all categories, starting // with Cookies. assertEquals(
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index 00256732..6523e80 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc
@@ -85,6 +85,10 @@ base::File patch_file, base::File output_file, const PatchFileBsdiffCallback& callback) override { + DCHECK(input_file.IsValid()); + DCHECK(patch_file.IsValid()); + DCHECK(output_file.IsValid()); + const int patch_result_status = bsdiff::ApplyBinaryPatch( std::move(input_file), std::move(patch_file), std::move(output_file)); callback.Run(patch_result_status); @@ -94,6 +98,10 @@ base::File patch_file, base::File output_file, const PatchFileCourgetteCallback& callback) override { + DCHECK(input_file.IsValid()); + DCHECK(patch_file.IsValid()); + DCHECK(output_file.IsValid()); + const int patch_result_status = courgette::ApplyEnsemblePatch( std::move(input_file), std::move(patch_file), std::move(output_file)); callback.Run(patch_result_status);
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index aff4184..d88ee0a 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -107,6 +107,15 @@ "CastMediaBlockerBrowserTest.Audio_BlockUnblock", ] } + + # TODO(mbjorge): Temporarily disable AudioPlaybackWavPcm because it is + # failing on device. As part of an effort to re-green the unittests, + # current (2017-03-15) failures are being disabled to get back to a + # green state. Re-enable once the tests have been fixed. + # b/36239152, hotlist/461351 + if (enable_assistant && !is_cast_desktop_build) { + gtest_excludes += [ "CastNavigationBrowserTest.AudioPlaybackWavPcm" ] + } } filters += [ cast_shell_browsertests_filter ]
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc index 5ffa05c..e9555094 100644 --- a/components/arc/test/fake_app_instance.cc +++ b/components/arc/test/fake_app_instance.cc
@@ -119,6 +119,12 @@ return true; } +void FakeAppInstance::GenerateAndSendBadIcon(const mojom::AppInfo& app, + mojom::ScaleFactor scale_factor) { + std::vector<uint8_t> badIcon(10, 1); + app_host_->OnAppIcon(app.package_name, app.activity, scale_factor, badIcon); +} + bool FakeAppInstance::GetFakeIcon(mojom::ScaleFactor scale_factor, std::string* png_data_as_string) { CHECK(png_data_as_string != nullptr);
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h index 4557cad..b4d5a29f 100644 --- a/components/arc/test/fake_app_instance.h +++ b/components/arc/test/fake_app_instance.h
@@ -125,6 +125,8 @@ bool GenerateAndSendIcon(const mojom::AppInfo& app, mojom::ScaleFactor scale_factor, std::string* png_data_as_string); + void GenerateAndSendBadIcon(const mojom::AppInfo& app, + mojom::ScaleFactor scale_factor); void SendInstallShortcut(const mojom::ShortcutInfo& shortcuts); void SendInstallShortcuts(const std::vector<mojom::ShortcutInfo>& shortcuts); void SetTaskInfo(int32_t task_id,
diff --git a/components/crash/content/app/crashpad.cc b/components/crash/content/app/crashpad.cc index 76f6734..dcec34684 100644 --- a/components/crash/content/app/crashpad.cc +++ b/components/crash/content/app/crashpad.cc
@@ -204,6 +204,12 @@ } #endif // OS_WIN +crashpad::CrashpadClient& GetCrashpadClient() { + static crashpad::CrashpadClient* const client = + new crashpad::CrashpadClient(); + return *client; +} + void SetUploadConsent(bool consent) { if (!g_database) return;
diff --git a/components/crash/content/app/crashpad.h b/components/crash/content/app/crashpad.h index eeb65ac..ada0eaec 100644 --- a/components/crash/content/app/crashpad.h +++ b/components/crash/content/app/crashpad.h
@@ -12,6 +12,15 @@ #include <vector> #include "base/files/file_path.h" +#include "build/build_config.h" + +#if defined(OS_MACOSX) +#include "base/mac/scoped_mach_port.h" +#endif + +namespace crashpad { +class CrashpadClient; +} namespace crash_reporter { @@ -55,6 +64,10 @@ const std::string& process_type); #endif // OS_WIN +// Returns the CrashpadClient for this process. This will lazily create it if +// it does not already exist. This is called as part of InitializeCrashpad. +crashpad::CrashpadClient& GetCrashpadClient(); + // Enables or disables crash report upload, taking the given consent to upload // into account. Consent may be ignored, uploads may not be enabled even with // consent, but will only be enabled without consent when policy enforces crash
diff --git a/components/crash/content/app/crashpad_mac.mm b/components/crash/content/app/crashpad_mac.mm index 7df66ea..2cabccb 100644 --- a/components/crash/content/app/crashpad_mac.mm +++ b/components/crash/content/app/crashpad_mac.mm
@@ -90,15 +90,9 @@ "--reset-own-crash-exception-port-to-system-default"); } - crashpad::CrashpadClient crashpad_client; - bool result = crashpad_client.StartHandler(handler_path, - database_path, - metrics_path, - url, - process_annotations, - arguments, - true, - false); + bool result = GetCrashpadClient().StartHandler( + handler_path, database_path, metrics_path, url, process_annotations, + arguments, true, false); // If this is an initial client that's not the browser process, it's // important to sever the connection to any existing handler. If
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc index 6d01b28..fa50b01 100644 --- a/components/crash/content/app/crashpad_win.cc +++ b/components/crash/content/app/crashpad_win.cc
@@ -9,7 +9,6 @@ #include "base/debug/crash_logging.h" #include "base/environment.h" #include "base/files/file_util.h" -#include "base/lazy_instance.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" @@ -26,13 +25,6 @@ namespace crash_reporter { namespace internal { -namespace { - -base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - void GetPlatformCrashpadAnnotations( std::map<std::string, std::string>* annotations) { CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); @@ -116,20 +108,19 @@ exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe")); } - g_crashpad_client.Get().StartHandler(exe_file, database_path, metrics_path, - url, process_annotations, arguments, - false, false); + GetCrashpadClient().StartHandler(exe_file, database_path, metrics_path, url, + process_annotations, arguments, false, + false); // If we're the browser, push the pipe name into the environment so child // processes can connect to it. If we inherited another crashpad_handler's // pipe name, we'll overwrite it here. env->SetVar(kPipeNameVar, - base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe())); + base::UTF16ToUTF8(GetCrashpadClient().GetHandlerIPCPipe())); } else { std::string pipe_name_utf8; if (env->GetVar(kPipeNameVar, &pipe_name_utf8)) { - g_crashpad_client.Get().SetHandlerIPCPipe( - base::UTF8ToUTF16(pipe_name_utf8)); + GetCrashpadClient().SetHandlerIPCPipe(base::UTF8ToUTF16(pipe_name_utf8)); } } @@ -218,7 +209,7 @@ // releases of Chrome. Please contact syzygy-team@chromium.org before doing so! int __declspec(dllexport) CrashForException( EXCEPTION_POINTERS* info) { - crash_reporter::internal::g_crashpad_client.Get().DumpAndCrash(info); + crash_reporter::GetCrashpadClient().DumpAndCrash(info); return EXCEPTION_CONTINUE_SEARCH; }
diff --git a/components/exo/display.cc b/components/exo/display.cc index ae02686..1fbab0f 100644 --- a/components/exo/display.cc +++ b/components/exo/display.cc
@@ -179,7 +179,6 @@ std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface( Surface* surface, - const gfx::Point& origin, int container) { TRACE_EVENT2("exo", "Display::CreateRemoteShellSurface", "surface", surface->AsTracedValue(), "container", container); @@ -193,7 +192,7 @@ bool can_minimize = container != ash::kShellWindowId_SystemModalContainer; return base::MakeUnique<ShellSurface>( - surface, nullptr, ShellSurface::BoundsMode::CLIENT, origin, + surface, nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(), true /* activatable */, can_minimize, container); }
diff --git a/components/exo/display.h b/components/exo/display.h index 7e9ee4e..780f4040 100644 --- a/components/exo/display.h +++ b/components/exo/display.h
@@ -76,7 +76,6 @@ // Creates a remote shell surface for an existing surface using |container|. std::unique_ptr<ShellSurface> CreateRemoteShellSurface( Surface* surface, - const gfx::Point& origin, int container); // Creates a sub-surface for an existing surface. The sub-surface will be
diff --git a/components/exo/display_unittest.cc b/components/exo/display_unittest.cc index 81792d8..24508ede 100644 --- a/components/exo/display_unittest.cc +++ b/components/exo/display_unittest.cc
@@ -147,13 +147,12 @@ // Create a remote shell surface for surface1. std::unique_ptr<ShellSurface> shell_surface1 = display->CreateRemoteShellSurface( - surface1.get(), gfx::Point(), - ash::kShellWindowId_SystemModalContainer); + surface1.get(), ash::kShellWindowId_SystemModalContainer); EXPECT_TRUE(shell_surface1); // Create a remote shell surface for surface2. std::unique_ptr<ShellSurface> shell_surface2 = - display->CreateRemoteShellSurface(surface2.get(), gfx::Point(), + display->CreateRemoteShellSurface(surface2.get(), ash::kShellWindowId_DefaultContainer); EXPECT_TRUE(shell_surface2); }
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 8b61a9d..7016042 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -10,8 +10,10 @@ #include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm/window_resizer.h" #include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/wm/drag_window_resizer.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/logging.h" @@ -29,6 +31,8 @@ #include "ui/aura/window_tree_host.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/class_property.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/path.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" @@ -143,6 +147,27 @@ DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter); }; +// Minimal WindowResizer that unlike DefaultWindowResizer does not handle +// dragging and resizing windows. +class CustomWindowResizer : public ash::WindowResizer { + public: + explicit CustomWindowResizer(ash::wm::WindowState* window_state) + : WindowResizer(window_state), shell_(GetTarget()->GetShell()) { + shell_->LockCursor(); + } + ~CustomWindowResizer() override { shell_->UnlockCursor(); } + + // Overridden from ash::WindowResizer: + void Drag(const gfx::Point& location, int event_flags) override {} + void CompleteDrag() override {} + void RevertDrag() override {} + + private: + ash::WmShell* const shell_; + + DISALLOW_COPY_AND_ASSIGN(CustomWindowResizer); +}; + class ShellSurfaceWidget : public views::Widget { public: explicit ShellSurfaceWidget(ShellSurface* shell_surface) @@ -299,11 +324,14 @@ surface_(surface), parent_(parent ? parent->GetWidget()->GetNativeWindow() : nullptr), bounds_mode_(bounds_mode), + primary_display_id_( + display::Screen::GetScreen()->GetPrimaryDisplay().id()), origin_(origin), activatable_(activatable), can_minimize_(can_minimize), container_(container) { WMHelper::GetInstance()->AddActivationObserver(this); + WMHelper::GetInstance()->AddDisplayConfigurationObserver(this); surface_->SetSurfaceDelegate(this); surface_->AddSurfaceObserver(this); surface_->window()->Show(); @@ -336,6 +364,7 @@ widget_->CloseNow(); } WMHelper::GetInstance()->RemoveActivationObserver(this); + WMHelper::GetInstance()->RemoveDisplayConfigurationObserver(this); if (parent_) parent_->RemoveObserver(this); if (surface_) { @@ -542,9 +571,9 @@ switch (bounds_mode_) { case BoundsMode::SHELL: + case BoundsMode::CLIENT: AttemptToStartDrag(HTCAPTION); return; - case BoundsMode::CLIENT: case BoundsMode::FIXED: return; } @@ -644,29 +673,7 @@ void ShellSurface::SetOrigin(const gfx::Point& origin) { TRACE_EVENT1("exo", "ShellSurface::SetOrigin", "origin", origin.ToString()); - if (origin == origin_) - return; - - if (bounds_mode_ != BoundsMode::CLIENT) { - origin_ = origin; - return; - } - - // If the origin changed, give the client a chance to adjust window positions - // before switching to the new coordinate system. Retain the old origin by - // reverting the origin delta until the next configure is acknowledged. - gfx::Vector2d delta = origin - origin_; - origin_offset_ -= delta; - pending_origin_offset_accumulator_ += delta; - origin_ = origin; - - if (widget_) { - UpdateWidgetBounds(); - UpdateShadow(); - } - - Configure(); } void ShellSurface::SetActivatable(bool activatable) { @@ -913,8 +920,8 @@ // the client to inform us that a frame has taken the state change into // account and without this cross-fade animations are unreliable. - // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the - // client, the configure callback does not yet support window state changes. + // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does + // not yet support window state changes. See crbug.com/699746. if (configure_callback_.is_null() || bounds_mode_ == BoundsMode::CLIENT) scoped_animations_disabled_.reset(new ScopedAnimationsDisabled(this)); } @@ -947,8 +954,8 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) { - // TODO(domlaskowski): For shell surfaces whose bounds are controlled by the - // client, the configure callback does not yet support resizing. + // TODO(domlaskowski): For BoundsMode::CLIENT, the configure callback does not + // yet support resizing. See crbug.com/699746. if (bounds_mode_ == BoundsMode::CLIENT) return; @@ -1013,6 +1020,39 @@ } //////////////////////////////////////////////////////////////////////////////// +// WMHelper::DisplayConfigurationObserver overrides: + +void ShellSurface::OnDisplayConfigurationChanged() { + if (bounds_mode_ != BoundsMode::CLIENT) + return; + + const display::Screen* screen = display::Screen::GetScreen(); + int64_t primary_display_id = screen->GetPrimaryDisplay().id(); + if (primary_display_id == primary_display_id_) + return; + + display::Display old_primary_display; + if (screen->GetDisplayWithDisplayId(primary_display_id_, + &old_primary_display)) { + // Give the client a chance to adjust window positions before switching to + // the new coordinate system. Retain the old origin by reverting the origin + // delta until the next configure is acknowledged. + gfx::Vector2d delta = gfx::Point() - old_primary_display.bounds().origin(); + origin_offset_ -= delta; + pending_origin_offset_accumulator_ += delta; + + if (widget_) { + UpdateWidgetBounds(); + UpdateShadow(); + } + + Configure(); + } + + primary_display_id_ = primary_display_id; +} + +//////////////////////////////////////////////////////////////////////////////// // ui::EventHandler overrides: void ShellSurface::OnKeyEvent(ui::KeyEvent* event) { @@ -1021,6 +1061,9 @@ return; } + // TODO(domlaskowski): For BoundsMode::CLIENT, synchronize the revert with the + // client, instead of having the client destroy the window on VKEY_ESCAPE. See + // crbug.com/699746. if (event->type() == ui::ET_KEY_PRESSED && event->key_code() == ui::VKEY_ESCAPE) { EndDrag(true /* revert */); @@ -1050,6 +1093,9 @@ switch (event->type()) { case ui::ET_MOUSE_DRAGGED: { + if (bounds_mode_ == BoundsMode::CLIENT) + break; + gfx::Point location(event->location()); aura::Window::ConvertPointToTarget(widget_->GetNativeWindow(), widget_->GetNativeWindow()->parent(), @@ -1203,11 +1249,11 @@ serial = configure_callback_.Run( non_client_view->frame_view()->GetBoundsForClientView().size(), ash::wm::GetWindowState(widget_->GetNativeWindow())->GetStateType(), - IsResizing(), widget_->IsActive(), origin_); + IsResizing(), widget_->IsActive(), origin_offset); } else { serial = configure_callback_.Run(gfx::Size(), ash::wm::WINDOW_STATE_TYPE_NORMAL, false, - false, origin_); + false, origin_offset); } } @@ -1225,6 +1271,22 @@ << pending_configs_.size(); } +aura::Window* ShellSurface::GetDragWindow() const { + switch (bounds_mode_) { + case BoundsMode::SHELL: + return widget_->GetNativeWindow(); + + case BoundsMode::CLIENT: + return surface_ ? surface_->window() : nullptr; + + case BoundsMode::FIXED: + return nullptr; + } + + NOTREACHED(); + return nullptr; +} + void ShellSurface::AttemptToStartDrag(int component) { DCHECK(widget_); @@ -1232,69 +1294,81 @@ if (resizer_) return; - if (widget_->GetNativeWindow()->HasCapture()) + aura::Window* window = GetDragWindow(); + if (!window || window->HasCapture()) return; - aura::Window* root_window = widget_->GetNativeWindow()->GetRootWindow(); - gfx::Point drag_location = - root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot(); - aura::Window::ConvertPointToTarget( - root_window, widget_->GetNativeWindow()->parent(), &drag_location); + if (bounds_mode_ == BoundsMode::SHELL) { + // Set the cursor before calling CreateWindowResizer(), as that will + // eventually call LockCursor() and prevent the cursor from changing. + aura::client::CursorClient* cursor_client = + aura::client::GetCursorClient(window->GetRootWindow()); + DCHECK(cursor_client); - // Set the cursor before calling CreateWindowResizer(), as that will - // eventually call LockCursor() and prevent the cursor from changing. - aura::client::CursorClient* cursor_client = - aura::client::GetCursorClient(root_window); - DCHECK(cursor_client); + switch (component) { + case HTCAPTION: + cursor_client->SetCursor(ui::kCursorPointer); + break; + case HTTOP: + cursor_client->SetCursor(ui::kCursorNorthResize); + break; + case HTTOPRIGHT: + cursor_client->SetCursor(ui::kCursorNorthEastResize); + break; + case HTRIGHT: + cursor_client->SetCursor(ui::kCursorEastResize); + break; + case HTBOTTOMRIGHT: + cursor_client->SetCursor(ui::kCursorSouthEastResize); + break; + case HTBOTTOM: + cursor_client->SetCursor(ui::kCursorSouthResize); + break; + case HTBOTTOMLEFT: + cursor_client->SetCursor(ui::kCursorSouthWestResize); + break; + case HTLEFT: + cursor_client->SetCursor(ui::kCursorWestResize); + break; + case HTTOPLEFT: + cursor_client->SetCursor(ui::kCursorNorthWestResize); + break; + default: + NOTREACHED(); + break; + } - switch (component) { - case HTCAPTION: - cursor_client->SetCursor(ui::kCursorPointer); - break; - case HTTOP: - cursor_client->SetCursor(ui::kCursorNorthResize); - break; - case HTTOPRIGHT: - cursor_client->SetCursor(ui::kCursorNorthEastResize); - break; - case HTRIGHT: - cursor_client->SetCursor(ui::kCursorEastResize); - break; - case HTBOTTOMRIGHT: - cursor_client->SetCursor(ui::kCursorSouthEastResize); - break; - case HTBOTTOM: - cursor_client->SetCursor(ui::kCursorSouthResize); - break; - case HTBOTTOMLEFT: - cursor_client->SetCursor(ui::kCursorSouthWestResize); - break; - case HTLEFT: - cursor_client->SetCursor(ui::kCursorWestResize); - break; - case HTTOPLEFT: - cursor_client->SetCursor(ui::kCursorNorthWestResize); - break; - default: - NOTREACHED(); - break; + resizer_ = ash::CreateWindowResizer(ash::WmWindow::Get(window), + GetMouseLocation(), component, + aura::client::WINDOW_MOVE_SOURCE_MOUSE); + if (!resizer_) + return; + + // Apply pending origin offsets and resize direction before starting a + // new resize operation. These can still be pending if the client has + // acknowledged the configure request but not yet called Commit(). + origin_offset_ += pending_origin_offset_; + pending_origin_offset_ = gfx::Vector2d(); + resize_component_ = pending_resize_component_; + } else { + DCHECK(bounds_mode_ == BoundsMode::CLIENT); + + ash::wm::WindowState* window_state = + ash::wm::GetWindowState(widget_->GetNativeWindow()); + DCHECK(!window_state->drag_details()); + DCHECK(component == HTCAPTION); + window_state->CreateDragDetails(GetMouseLocation(), component, + aura::client::WINDOW_MOVE_SOURCE_MOUSE); + + // Chained with a CustomWindowResizer, DragWindowResizer does not handle + // dragging. It only renders phantom windows and moves the window to the + // target root window when dragging ends. + resizer_.reset(ash::DragWindowResizer::Create( + new CustomWindowResizer(window_state), window_state)); } - resizer_ = ash::CreateWindowResizer( - ash::WmWindow::Get(widget_->GetNativeWindow()), drag_location, component, - aura::client::WINDOW_MOVE_SOURCE_MOUSE); - if (!resizer_) - return; - - // Apply pending origin offsets and resize direction before starting a new - // resize operation. These can still be pending if the client has acknowledged - // the configure request but not yet called Commit(). - origin_offset_ += pending_origin_offset_; - pending_origin_offset_ = gfx::Vector2d(); - resize_component_ = pending_resize_component_; - WMHelper::GetInstance()->AddPreTargetHandler(this); - widget_->GetNativeWindow()->SetCapture(); + window->SetCapture(); // Notify client that resizing state has changed. if (IsResizing()) @@ -1305,6 +1379,10 @@ DCHECK(widget_); DCHECK(resizer_); + aura::Window* window = GetDragWindow(); + DCHECK(window); + DCHECK(window->HasCapture()); + bool was_resizing = IsResizing(); if (revert) @@ -1313,7 +1391,7 @@ resizer_->CompleteDrag(); WMHelper::GetInstance()->RemovePreTargetHandler(this); - widget_->GetNativeWindow()->ReleaseCapture(); + window->ReleaseCapture(); resizer_.reset(); // Notify client that resizing state has changed. @@ -1426,8 +1504,32 @@ // should not result in a configure request. DCHECK(!ignore_window_bounds_changes_); ignore_window_bounds_changes_ = true; - if (widget_->GetWindowBoundsInScreen() != new_widget_bounds) - widget_->SetBounds(new_widget_bounds); + const gfx::Rect widget_bounds = widget_->GetWindowBoundsInScreen(); + if (widget_bounds != new_widget_bounds) { + if (bounds_mode_ != BoundsMode::CLIENT || !resizer_) { + widget_->SetBounds(new_widget_bounds); + UpdateSurfaceBounds(); + } else { + // TODO(domlaskowski): Synchronize window state transitions with the + // client, and abort client-side dragging on transition to fullscreen. See + // crbug.com/699746. + DLOG_IF(ERROR, widget_bounds.size() != new_widget_bounds.size()) + << "Window size changed during client-driven drag"; + + // Convert from screen to display coordinates. + gfx::Point origin = new_widget_bounds.origin(); + wm::ConvertPointFromScreen(widget_->GetNativeWindow()->parent(), &origin); + new_widget_bounds.set_origin(origin); + + // Move the window relative to the current display. + widget_->GetNativeWindow()->SetBounds(new_widget_bounds); + UpdateSurfaceBounds(); + + // Render phantom windows when beyond the current display. + resizer_->Drag(GetMouseLocation(), 0); + } + } + ignore_window_bounds_changes_ = false; } @@ -1591,4 +1693,13 @@ } } +gfx::Point ShellSurface::GetMouseLocation() const { + aura::Window* const root_window = widget_->GetNativeWindow()->GetRootWindow(); + gfx::Point location = + root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot(); + aura::Window::ConvertPointToTarget( + root_window, widget_->GetNativeWindow()->parent(), &location); + return location; +} + } // namespace exo
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index b090cae..c22947d 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_EXO_SHELL_SURFACE_H_ #define COMPONENTS_EXO_SHELL_SURFACE_H_ +#include <cstdint> #include <deque> #include <memory> #include <string> @@ -45,7 +46,8 @@ public ash::wm::WindowStateObserver, public aura::WindowObserver, public WMHelper::ActivationObserver, - public WMHelper::AccessibilityObserver { + public WMHelper::AccessibilityObserver, + public WMHelper::DisplayConfigurationObserver { public: enum class BoundsMode { SHELL, CLIENT, FIXED }; @@ -98,7 +100,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin)>; + const gfx::Vector2d& origin_offset)>; void set_configure_callback(const ConfigureCallback& configure_callback) { configure_callback_ = configure_callback; } @@ -250,6 +252,9 @@ // Overridden from WMHelper::AccessibilityObserver: void OnAccessibilityModeChanged() override; + // Overridden from WMHelper::DisplayConfigurationObserver: + void OnDisplayConfigurationChanged() override; + // Overridden from ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; void OnMouseEvent(ui::MouseEvent* event) override; @@ -280,6 +285,9 @@ // Asks the client to configure its surface. void Configure(); + // Returns the window that has capture during dragging. + aura::Window* GetDragWindow() const; + // Attempt to start a drag operation. The type of drag operation to start is // determined by |component|. void AttemptToStartDrag(int component); @@ -310,10 +318,14 @@ // Applies |system_modal_| to |widget_|. void UpdateSystemModal(); + // In the coordinate system of the parent root window. + gfx::Point GetMouseLocation() const; + views::Widget* widget_ = nullptr; Surface* surface_; aura::Window* parent_; const BoundsMode bounds_mode_; + int64_t primary_display_id_; gfx::Point origin_; bool activatable_ = true; const bool can_minimize_;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index 988a680..a7d018e 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -43,7 +43,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { EXPECT_EQ(ash::wm::WINDOW_STATE_TYPE_FULLSCREEN, state_type); return serial; } @@ -370,7 +370,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { *suggested_size = size; *has_state_type = state_type; *is_resizing = resizing;
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index b7a37dc..85a4b9a 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -1008,7 +1008,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { wl_shell_surface_send_configure(resource, WL_SHELL_SURFACE_RESIZE_NONE, size.width(), size.height()); wl_client_flush(wl_resource_get_client(resource)); @@ -1534,7 +1534,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { wl_array states; wl_array_init(&states); if (state_type == ash::wm::WINDOW_STATE_TYPE_MAXIMIZED) @@ -1672,7 +1672,7 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { wl_array states; wl_array_init(&states); if (state_type == ash::wm::WINDOW_STATE_TYPE_MAXIMIZED) @@ -1985,7 +1985,7 @@ } void remote_surface_move(wl_client* client, wl_resource* resource) { - NOTIMPLEMENTED(); + GetUserDataAs<ShellSurface>(resource)->Move(); } const struct zcr_remote_surface_v1_interface remote_surface_implementation = { @@ -2059,7 +2059,7 @@ std::unique_ptr<ShellSurface> CreateShellSurface(Surface* surface, int container) { - return display_->CreateRemoteShellSurface(surface, gfx::Point(), container); + return display_->CreateRemoteShellSurface(surface, container); } std::unique_ptr<NotificationSurface> CreateNotificationSurface( @@ -2069,9 +2069,20 @@ } // Overridden from display::DisplayObserver: + void OnDisplayAdded(const display::Display& new_display) override { + if (IsMultiDisplaySupported()) + ScheduleSendDisplayMetrics(0); + } + + void OnDisplayRemoved(const display::Display& old_display) override { + if (IsMultiDisplaySupported()) + ScheduleSendDisplayMetrics(0); + } + void OnDisplayMetricsChanged(const display::Display& display, uint32_t changed_metrics) override { - if (display::Screen::GetScreen()->GetPrimaryDisplay().id() != display.id()) + if (!IsMultiDisplaySupported() && + display::Screen::GetScreen()->GetPrimaryDisplay().id() != display.id()) return; // No need to update when a primary display has changed without bounds @@ -2116,9 +2127,31 @@ needs_send_display_metrics_ = false; const display::Screen* screen = display::Screen::GetScreen(); - const display::Display primary_display = screen->GetPrimaryDisplay(); + display::Display primary_display = screen->GetPrimaryDisplay(); - const gfx::Insets& work_area_insets = primary_display.GetWorkAreaInsets(); + if (IsMultiDisplaySupported()) { + for (const auto& display : screen->GetAllDisplays()) { + const gfx::Rect& bounds = display.bounds(); + const gfx::Insets& insets = display.GetWorkAreaInsets(); + + zcr_remote_shell_v1_send_workspace( + remote_shell_resource_, + static_cast<uint32_t>(display.id() >> 32), + static_cast<uint32_t>(display.id()), + bounds.x(), bounds.y(), bounds.width(), bounds.height(), + insets.left(), insets.top(), insets.right(), insets.bottom()); + } + + zcr_remote_shell_v1_send_configure( + remote_shell_resource_, + static_cast<uint32_t>(primary_display.id() >> 32), + static_cast<uint32_t>(primary_display.id()), + OutputTransform(primary_display.rotation()), + wl_fixed_from_double(primary_display.device_scale_factor()), + layout_mode_); + } + + const gfx::Insets& insets = primary_display.GetWorkAreaInsets(); zcr_remote_shell_v1_send_configuration_changed( remote_shell_resource_, @@ -2126,8 +2159,8 @@ primary_display.size().height(), OutputTransform(primary_display.rotation()), wl_fixed_from_double(primary_display.device_scale_factor()), - work_area_insets.left(), work_area_insets.top(), - work_area_insets.right(), work_area_insets.bottom(), layout_mode_); + insets.left(), insets.top(), insets.right(), insets.bottom(), + layout_mode_); wl_client_flush(wl_resource_get_client(remote_shell_resource_)); } @@ -2237,12 +2270,14 @@ ash::wm::WindowStateType state_type, bool resizing, bool activated, - const gfx::Point& origin) { + const gfx::Vector2d& origin_offset) { wl_array states; wl_array_init(&states); uint32_t serial = wl_display_next_serial( wl_client_get_display(wl_resource_get_client(resource))); - zcr_remote_surface_v1_send_configure(resource, origin.x(), origin.y(), + zcr_remote_surface_v1_send_configure(resource, + origin_offset.x(), + origin_offset.y(), &states, serial); wl_client_flush(wl_resource_get_client(resource)); wl_array_release(&states); @@ -2316,7 +2351,7 @@ remote_shell_destroy, remote_shell_get_remote_surface, remote_shell_get_notification_surface}; -const uint32_t remote_shell_version = 2; +const uint32_t remote_shell_version = 3; void bind_remote_shell(wl_client* client, void* data,
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc index 009d4cc..7f0cfcf 100644 --- a/components/exo/wm_helper.cc +++ b/components/exo/wm_helper.cc
@@ -79,6 +79,16 @@ input_device_event_observers_.RemoveObserver(observer); } +void WMHelper::AddDisplayConfigurationObserver( + DisplayConfigurationObserver* observer) { + display_config_observers_.AddObserver(observer); +} + +void WMHelper::RemoveDisplayConfigurationObserver( + DisplayConfigurationObserver* observer) { + display_config_observers_.RemoveObserver(observer); +} + void WMHelper::NotifyWindowActivated(aura::Window* gained_active, aura::Window* lost_active) { for (ActivationObserver& observer : activation_observers_) @@ -126,4 +136,9 @@ observer.OnKeyboardDeviceConfigurationChanged(); } +void WMHelper::NotifyDisplayConfigurationChanged() { + for (DisplayConfigurationObserver& observer : display_config_observers_) + observer.OnDisplayConfigurationChanged(); +} + } // namespace exo
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h index 9ce432b8..ad0aeb6a 100644 --- a/components/exo/wm_helper.h +++ b/components/exo/wm_helper.h
@@ -79,6 +79,14 @@ virtual ~InputDeviceEventObserver() {} }; + class DisplayConfigurationObserver { + public: + virtual void OnDisplayConfigurationChanged() = 0; + + protected: + virtual ~DisplayConfigurationObserver() {} + }; + virtual ~WMHelper(); static void SetInstance(WMHelper* helper); @@ -96,6 +104,9 @@ void RemoveAccessibilityObserver(AccessibilityObserver* observer); void AddInputDeviceEventObserver(InputDeviceEventObserver* observer); void RemoveInputDeviceEventObserver(InputDeviceEventObserver* observer); + void AddDisplayConfigurationObserver(DisplayConfigurationObserver* observer); + void RemoveDisplayConfigurationObserver( + DisplayConfigurationObserver* observer); virtual const display::ManagedDisplayInfo GetDisplayInfo( int64_t display_id) const = 0; @@ -126,6 +137,7 @@ void NotifyMaximizeModeEnded(); void NotifyAccessibilityModeChanged(); void NotifyKeyboardDeviceConfigurationChanged(); + void NotifyDisplayConfigurationChanged(); private: base::ObserverList<ActivationObserver> activation_observers_; @@ -134,6 +146,7 @@ base::ObserverList<MaximizeModeObserver> maximize_mode_observers_; base::ObserverList<AccessibilityObserver> accessibility_observers_; base::ObserverList<InputDeviceEventObserver> input_device_event_observers_; + base::ObserverList<DisplayConfigurationObserver> display_config_observers_; DISALLOW_COPY_AND_ASSIGN(WMHelper); };
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc index 6c305117..4fefebd5 100644 --- a/components/exo/wm_helper_ash.cc +++ b/components/exo/wm_helper_ash.cc
@@ -23,6 +23,7 @@ WMHelperAsh::WMHelperAsh() { ash::Shell::GetInstance()->AddShellObserver(this); ash::Shell::GetInstance()->activation_client()->AddObserver(this); + ash::Shell::GetInstance()->window_tree_host_manager()->AddObserver(this); aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->AddObserver(this); @@ -36,6 +37,7 @@ aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->RemoveObserver(this); + ash::Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this); ash::Shell::GetInstance()->activation_client()->RemoveObserver(this); ash::Shell::GetInstance()->RemoveShellObserver(this); ui::DeviceDataManager::GetInstance()->RemoveObserver(this); @@ -145,6 +147,10 @@ NotifyMaximizeModeEnded(); } +void WMHelperAsh::OnDisplayConfigurationChanged() { + NotifyDisplayConfigurationChanged(); +} + void WMHelperAsh::OnKeyboardDeviceConfigurationChanged() { NotifyKeyboardDeviceConfigurationChanged(); }
diff --git a/components/exo/wm_helper_ash.h b/components/exo/wm_helper_ash.h index b41e750..8b07843d 100644 --- a/components/exo/wm_helper_ash.h +++ b/components/exo/wm_helper_ash.h
@@ -7,6 +7,7 @@ #include "ash/common/shell_observer.h" #include "ash/common/system/accessibility_observer.h" +#include "ash/display/window_tree_host_manager.h" #include "base/macros.h" #include "components/exo/wm_helper.h" #include "ui/aura/client/cursor_client_observer.h" @@ -23,6 +24,7 @@ public aura::client::CursorClientObserver, public ash::AccessibilityObserver, public ash::ShellObserver, + public ash::WindowTreeHostManager::Observer, public ui::InputDeviceEventObserver { public: WMHelperAsh(); @@ -67,6 +69,9 @@ void OnMaximizeModeEnding() override; void OnMaximizeModeEnded() override; + // Overriden from ash::WindowTreeHostManager::Observer: + void OnDisplayConfigurationChanged() override; + // Overriden from ui::InputDeviceEventObserver: void OnKeyboardDeviceConfigurationChanged() override;
diff --git a/components/metrics/metrics_state_manager.cc b/components/metrics/metrics_state_manager.cc index 4cae20d3..83d62b5f 100644 --- a/components/metrics/metrics_state_manager.cc +++ b/components/metrics/metrics_state_manager.cc
@@ -92,16 +92,10 @@ client_id_.swap(client_id_from_prefs); } - if (!client_id_.empty()) { - // It is technically sufficient to only save a backup of the client id when - // it is initially generated below, but since the backup was only introduced - // in M38, seed it explicitly from here for some time. - BackUpCurrentClientInfo(); + if (!client_id_.empty()) return; - } - const std::unique_ptr<ClientInfo> client_info_backup = - LoadClientInfoAndMaybeMigrate(); + const std::unique_ptr<ClientInfo> client_info_backup = LoadClientInfo(); if (client_info_backup) { client_id_ = client_info_backup->client_id; @@ -233,36 +227,12 @@ store_client_info_.Run(client_info); } -std::unique_ptr<ClientInfo> -MetricsStateManager::LoadClientInfoAndMaybeMigrate() { +std::unique_ptr<ClientInfo> MetricsStateManager::LoadClientInfo() { std::unique_ptr<ClientInfo> client_info = load_client_info_.Run(); - // Prior to 2014-07, the client ID was stripped of its dashes before being - // saved. Migrate back to a proper GUID if this is the case. This migration - // code can be removed in M41+. - const size_t kGUIDLengthWithoutDashes = 32U; - if (client_info && - client_info->client_id.length() == kGUIDLengthWithoutDashes) { - DCHECK(client_info->client_id.find('-') == std::string::npos); - - std::string client_id_with_dashes; - client_id_with_dashes.reserve(kGUIDLengthWithoutDashes + 4U); - std::string::const_iterator client_id_it = client_info->client_id.begin(); - for (size_t i = 0; i < kGUIDLengthWithoutDashes + 4U; ++i) { - if (i == 8U || i == 13U || i == 18U || i == 23U) { - client_id_with_dashes.push_back('-'); - } else { - client_id_with_dashes.push_back(*client_id_it); - ++client_id_it; - } - } - DCHECK(client_id_it == client_info->client_id.end()); - client_info->client_id.assign(client_id_with_dashes); - } - - // The GUID retrieved (and possibly fixed above) should be valid unless - // retrieval failed. If not, return nullptr. This will result in a new GUID - // being generated by the calling function ForceClientIdCreation(). + // The GUID retrieved should be valid unless retrieval failed. + // If not, return nullptr. This will result in a new GUID being generated by + // the calling function ForceClientIdCreation(). if (client_info && !base::IsValidGUID(client_info->client_id)) return nullptr;
diff --git a/components/metrics/metrics_state_manager.h b/components/metrics/metrics_state_manager.h index afa146b9..ca60fd4 100644 --- a/components/metrics/metrics_state_manager.h +++ b/components/metrics/metrics_state_manager.h
@@ -118,9 +118,8 @@ // Backs up the current client info via |store_client_info_|. void BackUpCurrentClientInfo(); - // Loads the client info via |load_client_info_| and potentially migrates it - // before returning it if it comes back in its old form. - std::unique_ptr<ClientInfo> LoadClientInfoAndMaybeMigrate(); + // Loads the client info via |load_client_info_|. + std::unique_ptr<ClientInfo> LoadClientInfo(); // Returns the low entropy source for this client. This is a random value // that is non-identifying amongst browser clients. This method will
diff --git a/components/metrics/metrics_state_manager_unittest.cc b/components/metrics/metrics_state_manager_unittest.cc index bbef26b1..a55c2fa 100644 --- a/components/metrics/metrics_state_manager_unittest.cc +++ b/components/metrics/metrics_state_manager_unittest.cc
@@ -28,7 +28,8 @@ class MetricsStateManagerTest : public testing::Test { public: MetricsStateManagerTest() - : enabled_state_provider_(new TestEnabledStateProvider(false, false)) { + : test_begin_time_(base::Time::Now().ToTimeT()), + enabled_state_provider_(new TestEnabledStateProvider(false, false)) { MetricsService::RegisterPrefs(prefs_.registry()); } @@ -47,6 +48,21 @@ enabled_state_provider_->set_enabled(true); } + void SetClientInfoPrefs(const ClientInfo& client_info) { + prefs_.SetString(prefs::kMetricsClientID, client_info.client_id); + prefs_.SetInt64(prefs::kInstallDate, client_info.installation_date); + prefs_.SetInt64(prefs::kMetricsReportingEnabledTimestamp, + client_info.reporting_enabled_date); + } + + void SetFakeClientInfoBackup(const ClientInfo& client_info) { + fake_client_info_backup_.reset(new ClientInfo); + fake_client_info_backup_->client_id = client_info.client_id; + fake_client_info_backup_->installation_date = client_info.installation_date; + fake_client_info_backup_->reporting_enabled_date = + client_info.reporting_enabled_date; + } + protected: TestingPrefServiceSimple prefs_; @@ -58,6 +74,8 @@ // MetricsStateManager. std::unique_ptr<ClientInfo> fake_client_info_backup_; + const int64_t test_begin_time_; + private: // Stores the |client_info| in |stored_client_info_backup_| for verification // by the tests later. @@ -222,11 +240,6 @@ const int64_t kFakeInstallationDate = 12345; prefs_.SetInt64(prefs::kInstallDate, kFakeInstallationDate); - const int64_t test_begin_time = base::Time::Now().ToTimeT(); - - // Holds ClientInfo from previous scoped test for extra checks. - std::unique_ptr<ClientInfo> previous_client_info; - { std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); @@ -241,7 +254,7 @@ state_manager->ForceClientIdCreation(); EXPECT_NE(std::string(), state_manager->client_id()); EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp), - test_begin_time); + test_begin_time_); ASSERT_TRUE(stored_client_info_backup_); EXPECT_EQ(state_manager->client_id(), @@ -250,70 +263,82 @@ stored_client_info_backup_->installation_date); EXPECT_EQ(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp), stored_client_info_backup_->reporting_enabled_date); - - previous_client_info = std::move(stored_client_info_backup_); } +} + +TEST_F(MetricsStateManagerTest, LoadPrefs) { + ClientInfo client_info; + client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"; + client_info.installation_date = 1112; + client_info.reporting_enabled_date = 2223; + SetClientInfoPrefs(client_info); EnableMetricsReporting(); - { + EXPECT_FALSE(fake_client_info_backup_); EXPECT_FALSE(stored_client_info_backup_); std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); // client_id should be auto-obtained from the constructor when metrics // reporting is enabled. - EXPECT_EQ(previous_client_info->client_id, state_manager->client_id()); + EXPECT_EQ(client_info.client_id, state_manager->client_id()); - // The backup should also be refreshed when the client id re-initialized. - ASSERT_TRUE(stored_client_info_backup_); - EXPECT_EQ(previous_client_info->client_id, - stored_client_info_backup_->client_id); - EXPECT_EQ(kFakeInstallationDate, - stored_client_info_backup_->installation_date); - EXPECT_EQ(previous_client_info->reporting_enabled_date, - stored_client_info_backup_->reporting_enabled_date); + // The backup should not be modified. + ASSERT_FALSE(stored_client_info_backup_); // Re-forcing client id creation shouldn't cause another backup and // shouldn't affect the existing client id. - stored_client_info_backup_.reset(); state_manager->ForceClientIdCreation(); EXPECT_FALSE(stored_client_info_backup_); - EXPECT_EQ(previous_client_info->client_id, state_manager->client_id()); + EXPECT_EQ(client_info.client_id, state_manager->client_id()); } +} - const int64_t kBackupInstallationDate = 1111; - const int64_t kBackupReportingEnabledDate = 2222; - const char kBackupClientId[] = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"; - fake_client_info_backup_.reset(new ClientInfo); - fake_client_info_backup_->client_id = kBackupClientId; - fake_client_info_backup_->installation_date = kBackupInstallationDate; - fake_client_info_backup_->reporting_enabled_date = - kBackupReportingEnabledDate; +TEST_F(MetricsStateManagerTest, PreferPrefs) { + ClientInfo client_info; + client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"; + client_info.installation_date = 1112; + client_info.reporting_enabled_date = 2223; + SetClientInfoPrefs(client_info); + ClientInfo client_info2; + client_info2.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"; + client_info2.installation_date = 1111; + client_info2.reporting_enabled_date = 2222; + SetFakeClientInfoBackup(client_info2); + + EnableMetricsReporting(); { - // The existence of a backup should result in the same behaviour as - // before if we already have a client id. + // The backup should be ignored if we already have a client id. EXPECT_FALSE(stored_client_info_backup_); std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); - EXPECT_EQ(previous_client_info->client_id, state_manager->client_id()); + EXPECT_EQ(client_info.client_id, state_manager->client_id()); - // The backup should also be refreshed when the client id re-initialized. - ASSERT_TRUE(stored_client_info_backup_); - EXPECT_EQ(previous_client_info->client_id, - stored_client_info_backup_->client_id); - EXPECT_EQ(kFakeInstallationDate, - stored_client_info_backup_->installation_date); - EXPECT_EQ(previous_client_info->reporting_enabled_date, - stored_client_info_backup_->reporting_enabled_date); - stored_client_info_backup_.reset(); + // The backup should not be modified. + ASSERT_FALSE(stored_client_info_backup_); } +} + +TEST_F(MetricsStateManagerTest, RestoreBackup) { + ClientInfo client_info; + client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"; + client_info.installation_date = 1112; + client_info.reporting_enabled_date = 2223; + SetClientInfoPrefs(client_info); + + ClientInfo client_info2; + client_info2.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"; + client_info2.installation_date = 1111; + client_info2.reporting_enabled_date = 2222; + SetFakeClientInfoBackup(client_info2); prefs_.ClearPref(prefs::kMetricsClientID); prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp); + EnableMetricsReporting(); { // The backup should kick in if the client id has gone missing. It should // replace remaining and missing dates as well. @@ -321,62 +346,46 @@ EXPECT_FALSE(stored_client_info_backup_); std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); - EXPECT_EQ(kBackupClientId, state_manager->client_id()); - EXPECT_EQ(kBackupInstallationDate, prefs_.GetInt64(prefs::kInstallDate)); - EXPECT_EQ(kBackupReportingEnabledDate, + EXPECT_EQ(client_info2.client_id, state_manager->client_id()); + EXPECT_EQ(client_info2.installation_date, + prefs_.GetInt64(prefs::kInstallDate)); + EXPECT_EQ(client_info2.reporting_enabled_date, prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp)); EXPECT_TRUE(stored_client_info_backup_); - stored_client_info_backup_.reset(); } +} - const char kNoDashesBackupClientId[] = "AAAAAAAABBBBCCCCDDDDEEEEEEEEEEEE"; - fake_client_info_backup_.reset(new ClientInfo); - fake_client_info_backup_->client_id = kNoDashesBackupClientId; +TEST_F(MetricsStateManagerTest, ResetBackup) { + ClientInfo client_info; + client_info.client_id = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"; + client_info.installation_date = 1111; + client_info.reporting_enabled_date = 2222; - prefs_.ClearPref(prefs::kInstallDate); - prefs_.ClearPref(prefs::kMetricsClientID); - prefs_.ClearPref(prefs::kMetricsReportingEnabledTimestamp); - - { - // When running the backup from old-style client ids, dashes should be - // re-added. And missing dates in backup should be replaced by Time::Now(). - - EXPECT_FALSE(stored_client_info_backup_); - - std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); - EXPECT_EQ(kBackupClientId, state_manager->client_id()); - EXPECT_GE(prefs_.GetInt64(prefs::kInstallDate), test_begin_time); - EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp), - test_begin_time); - - EXPECT_TRUE(stored_client_info_backup_); - previous_client_info = std::move(stored_client_info_backup_); - } + SetFakeClientInfoBackup(client_info); + SetClientInfoPrefs(client_info); prefs_.SetBoolean(prefs::kMetricsResetIds, true); + EnableMetricsReporting(); { // Upon request to reset metrics ids, the existing backup should not be // restored. - EXPECT_FALSE(stored_client_info_backup_); - std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager()); // A brand new client id should have been generated. EXPECT_NE(std::string(), state_manager->client_id()); - EXPECT_NE(previous_client_info->client_id, state_manager->client_id()); + EXPECT_NE(client_info.client_id, state_manager->client_id()); + EXPECT_TRUE(stored_client_info_backup_); // The installation date should not have been affected. - EXPECT_EQ(previous_client_info->installation_date, + EXPECT_EQ(client_info.installation_date, prefs_.GetInt64(prefs::kInstallDate)); // The metrics-reporting-enabled date will be reset to Now(). EXPECT_GE(prefs_.GetInt64(prefs::kMetricsReportingEnabledTimestamp), - previous_client_info->reporting_enabled_date); - - stored_client_info_backup_.reset(); + test_begin_time_); } }
diff --git a/components/prefs/json_pref_store.cc b/components/prefs/json_pref_store.cc index a9a3922..cf4d2a3 100644 --- a/components/prefs/json_pref_store.cc +++ b/components/prefs/json_pref_store.cc
@@ -111,13 +111,7 @@ } std::unique_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk( - const base::FilePath& path, - const base::FilePath& alternate_path) { - if (!base::PathExists(path) && !alternate_path.empty() && - base::PathExists(alternate_path)) { - base::Move(alternate_path, path); - } - + const base::FilePath& path) { int error_code; std::string error_msg; std::unique_ptr<JsonPrefStore::ReadResult> read_result( @@ -151,18 +145,7 @@ const base::FilePath& pref_filename, const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, std::unique_ptr<PrefFilter> pref_filter) - : JsonPrefStore(pref_filename, - base::FilePath(), - sequenced_task_runner, - std::move(pref_filter)) {} - -JsonPrefStore::JsonPrefStore( - const base::FilePath& pref_filename, - const base::FilePath& pref_alternate_filename, - const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, - std::unique_ptr<PrefFilter> pref_filter) : path_(pref_filename), - alternate_path_(pref_alternate_filename), sequenced_task_runner_(sequenced_task_runner), prefs_(new base::DictionaryValue()), read_only_(false), @@ -283,7 +266,7 @@ PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { DCHECK(CalledOnValidThread()); - OnFileRead(ReadPrefsFromDisk(path_, alternate_path_)); + OnFileRead(ReadPrefsFromDisk(path_)); return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE : read_error_; } @@ -296,9 +279,8 @@ // Weakly binds the read task so that it doesn't kick in during shutdown. base::PostTaskAndReplyWithResult( - sequenced_task_runner_.get(), - FROM_HERE, - base::Bind(&ReadPrefsFromDisk, path_, alternate_path_), + sequenced_task_runner_.get(), FROM_HERE, + base::Bind(&ReadPrefsFromDisk, path_), base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr())); }
diff --git a/components/prefs/json_pref_store.h b/components/prefs/json_pref_store.h index 8c1164c..6284b8d5 100644 --- a/components/prefs/json_pref_store.h +++ b/components/prefs/json_pref_store.h
@@ -62,22 +62,11 @@ const base::FilePath& pref_filename, base::SequencedWorkerPool* worker_pool); - // Same as the constructor below with no alternate filename. - JsonPrefStore( - const base::FilePath& pref_filename, - const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, - std::unique_ptr<PrefFilter> pref_filter); - // |sequenced_task_runner| must be a shutdown-blocking task runner, ideally // created by the GetTaskRunnerForFile() method above. // |pref_filename| is the path to the file to read prefs from. - // |pref_alternate_filename| is the path to an alternate file which the - // desired prefs may have previously been written to. If |pref_filename| - // doesn't exist and |pref_alternate_filename| does, |pref_alternate_filename| - // will be moved to |pref_filename| before the read occurs. JsonPrefStore( const base::FilePath& pref_filename, - const base::FilePath& pref_alternate_filename, const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, std::unique_ptr<PrefFilter> pref_filter); @@ -231,7 +220,6 @@ void ScheduleWrite(uint32_t flags); const base::FilePath path_; - const base::FilePath alternate_path_; const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; std::unique_ptr<base::DictionaryValue> prefs_;
diff --git a/components/prefs/json_pref_store_unittest.cc b/components/prefs/json_pref_store_unittest.cc index 0164ad6..cae79d3 100644 --- a/components/prefs/json_pref_store_unittest.cc +++ b/components/prefs/json_pref_store_unittest.cc
@@ -166,21 +166,6 @@ EXPECT_FALSE(pref_store->ReadOnly()); } -// Test fallback behavior for a nonexistent file and alternate file. -TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) { - base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt"); - base::FilePath bogus_alternate_input_file = - temp_dir_.GetPath().AppendASCII("read_alternate.txt"); - ASSERT_FALSE(PathExists(bogus_input_file)); - ASSERT_FALSE(PathExists(bogus_alternate_input_file)); - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( - bogus_input_file, bogus_alternate_input_file, message_loop_.task_runner(), - std::unique_ptr<PrefFilter>()); - EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, - pref_store->ReadPrefs()); - EXPECT_FALSE(pref_store->ReadOnly()); -} - // Test fallback behavior for an invalid file. TEST_F(JsonPrefStoreTest, InvalidFile) { base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json"); @@ -518,171 +503,6 @@ RunBasicJsonPrefStoreTest(pref_store.get(), input_file); } -TEST_F(JsonPrefStoreTest, AlternateFile) { - base::FilePath alternate_input_file = - temp_dir_.GetPath().AppendASCII("alternate.json"); - ASSERT_LT(0, base::WriteFile(alternate_input_file, - kReadJson, arraysize(kReadJson) - 1)); - - // Test that the alternate file is moved to the main file and read as-is from - // there. - base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json"); - ASSERT_FALSE(PathExists(input_file)); - ASSERT_TRUE(PathExists(alternate_input_file)); - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( - input_file, alternate_input_file, message_loop_.task_runner(), - std::unique_ptr<PrefFilter>()); - - ASSERT_FALSE(PathExists(input_file)); - ASSERT_TRUE(PathExists(alternate_input_file)); - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_FALSE(PathExists(alternate_input_file)); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest(pref_store.get(), input_file); -} - -TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) { - base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json"); - ASSERT_LT(0, base::WriteFile(input_file, - kReadJson, arraysize(kReadJson) - 1)); - - base::FilePath alternate_input_file = - temp_dir_.GetPath().AppendASCII("alternate.json"); - ASSERT_LT(0, base::WriteFile(alternate_input_file, - kInvalidJson, arraysize(kInvalidJson) - 1)); - - // Test that the alternate file is ignored and that the read occurs from the - // existing main file. There is no attempt at even deleting the alternate - // file as this scenario should never happen in normal user-data-dirs. - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( - input_file, alternate_input_file, message_loop_.task_runner(), - std::unique_ptr<PrefFilter>()); - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_TRUE(PathExists(alternate_input_file)); - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_TRUE(PathExists(alternate_input_file)); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest(pref_store.get(), input_file); -} - -TEST_F(JsonPrefStoreTest, AlternateFileDNE) { - base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json"); - ASSERT_LT(0, base::WriteFile(input_file, - kReadJson, arraysize(kReadJson) - 1)); - - // Test that the basic read works fine when an alternate file is specified but - // does not exist. - base::FilePath alternate_input_file = - temp_dir_.GetPath().AppendASCII("alternate.json"); - ASSERT_TRUE(PathExists(input_file)); - ASSERT_FALSE(PathExists(alternate_input_file)); - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( - input_file, alternate_input_file, message_loop_.task_runner(), - std::unique_ptr<PrefFilter>()); - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_FALSE(PathExists(alternate_input_file)); - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_FALSE(PathExists(alternate_input_file)); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest(pref_store.get(), input_file); -} - -TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) { - base::FilePath alternate_input_file = - temp_dir_.GetPath().AppendASCII("alternate.json"); - ASSERT_LT(0, base::WriteFile(alternate_input_file, - kReadJson, arraysize(kReadJson) - 1)); - - // Test that the alternate file is moved to the main file and read as-is from - // there even when the read is made asynchronously. - base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json"); - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore( - input_file, alternate_input_file, message_loop_.task_runner(), - std::unique_ptr<PrefFilter>()); - - ASSERT_FALSE(PathExists(input_file)); - ASSERT_TRUE(PathExists(alternate_input_file)); - - { - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - - MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; - pref_store->ReadPrefsAsync(mock_error_delegate); - - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - EXPECT_CALL(*mock_error_delegate, - OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); - RunLoop().RunUntilIdle(); - pref_store->RemoveObserver(&mock_observer); - - EXPECT_FALSE(pref_store->ReadOnly()); - EXPECT_TRUE(pref_store->IsInitializationComplete()); - } - - ASSERT_TRUE(PathExists(input_file)); - ASSERT_FALSE(PathExists(alternate_input_file)); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest(pref_store.get(), input_file); -} - TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) { base::HistogramTester histogram_tester;
diff --git a/components/sync/android/java/src/org/chromium/components/sync/notifier/RandomizedInvalidationClientNameGenerator.java b/components/sync/android/java/src/org/chromium/components/sync/notifier/RandomizedInvalidationClientNameGenerator.java index faf597c..bbcbaf6 100644 --- a/components/sync/android/java/src/org/chromium/components/sync/notifier/RandomizedInvalidationClientNameGenerator.java +++ b/components/sync/android/java/src/org/chromium/components/sync/notifier/RandomizedInvalidationClientNameGenerator.java
@@ -32,6 +32,7 @@ * However, as bad as it is, this ID is better than a hard-coded default or none at all. See * the class description for more details. */ + @Override public byte[] generateInvalidatorClientName() { byte[] randomBytes = new byte[8]; RANDOM.nextBytes(randomBytes);
diff --git a/components/translate/core/browser/translate_ranker.cc b/components/translate/core/browser/translate_ranker.cc index 1341652..dd934110 100644 --- a/components/translate/core/browser/translate_ranker.cc +++ b/components/translate/core/browser/translate_ranker.cc
@@ -80,7 +80,7 @@ "TranslateRankerEnforcement", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kTranslateRankerLogging{"TranslateRankerLogging", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; TranslateRanker::~TranslateRanker() {}
diff --git a/components/translate/core/browser/translate_ranker_unittest.cc b/components/translate/core/browser/translate_ranker_unittest.cc index 495a1b861..3a48529 100644 --- a/components/translate/core/browser/translate_ranker_unittest.cc +++ b/components/translate/core/browser/translate_ranker_unittest.cc
@@ -143,7 +143,7 @@ TEST_F(TranslateRankerTest, EnableQueryAndEnforcement) { InitFeatures({kTranslateRankerQuery, kTranslateRankerEnforcement}, {}); EXPECT_TRUE(TranslateRanker::IsEnabled()); - EXPECT_FALSE(TranslateRanker::IsLoggingEnabled()); + EXPECT_TRUE(TranslateRanker::IsLoggingEnabled()); } TEST_F(TranslateRankerTest, EnableLogging) { @@ -186,7 +186,6 @@ } TEST_F(TranslateRankerTest, RecordAndFlushEvents) { - InitFeatures({kTranslateRankerLogging}, {}); std::unique_ptr<translate::TranslateRanker> ranker = GetRankerForTest(0.0f); std::vector<metrics::TranslateEventProto> flushed_events;
diff --git a/components/user_prefs/tracked/mock_validation_delegate.cc b/components/user_prefs/tracked/mock_validation_delegate.cc index 4362f991..c82deb5 100644 --- a/components/user_prefs/tracked/mock_validation_delegate.cc +++ b/components/user_prefs/tracked/mock_validation_delegate.cc
@@ -63,7 +63,7 @@ bool is_personal) { record_->RecordValidation(pref_path, value_state, external_validation_value_state, is_personal, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC); + PrefHashFilter::PrefTrackingStrategy::ATOMIC); } void MockValidationDelegate::OnSplitPreferenceValidation( @@ -75,5 +75,5 @@ bool is_personal) { record_->RecordValidation(pref_path, value_state, external_validation_value_state, is_personal, - PrefHashFilter::TRACKING_STRATEGY_SPLIT); + PrefHashFilter::PrefTrackingStrategy::SPLIT); }
diff --git a/components/user_prefs/tracked/pref_hash_filter.cc b/components/user_prefs/tracked/pref_hash_filter.cc index 8056b749..44a8ec5 100644 --- a/components/user_prefs/tracked/pref_hash_filter.cc +++ b/components/user_prefs/tracked/pref_hash_filter.cc
@@ -78,7 +78,7 @@ std::unique_ptr<TrackedPreference> tracked_preference; switch (metadata.strategy) { - case TRACKING_STRATEGY_ATOMIC: + case PrefTrackingStrategy::ATOMIC: tracked_preference.reset( new TrackedAtomicPreference(metadata.name, metadata.reporting_id, @@ -87,7 +87,7 @@ metadata.value_type, delegate)); break; - case TRACKING_STRATEGY_SPLIT: + case PrefTrackingStrategy::SPLIT: tracked_preference.reset( new TrackedSplitPreference(metadata.name, metadata.reporting_id,
diff --git a/components/user_prefs/tracked/pref_hash_filter.h b/components/user_prefs/tracked/pref_hash_filter.h index 87c3f03..d7addb9 100644 --- a/components/user_prefs/tracked/pref_hash_filter.h +++ b/components/user_prefs/tracked/pref_hash_filter.h
@@ -45,21 +45,21 @@ // are changed. class PrefHashFilter : public InterceptablePrefFilter { public: - enum EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD }; + enum class EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD }; - enum PrefTrackingStrategy { + enum class PrefTrackingStrategy { // Atomic preferences are tracked as a whole. - TRACKING_STRATEGY_ATOMIC, + ATOMIC, // Split preferences are dictionaries for which each top-level entry is // tracked independently. Note: preferences using this strategy must be kept // in sync with TrackedSplitPreferences in histograms.xml. - TRACKING_STRATEGY_SPLIT, + SPLIT, }; - enum ValueType { - VALUE_IMPERSONAL, + enum class ValueType { + IMPERSONAL, // The preference value may contain personal information. - VALUE_PERSONAL, + PERSONAL, }; struct TrackedPreferenceMetadata {
diff --git a/components/user_prefs/tracked/pref_hash_filter_unittest.cc b/components/user_prefs/tracked/pref_hash_filter_unittest.cc index 604471f..a3c701b 100644 --- a/components/user_prefs/tracked/pref_hash_filter_unittest.cc +++ b/components/user_prefs/tracked/pref_hash_filter_unittest.cc
@@ -33,6 +33,10 @@ namespace { +using EnforcementLevel = PrefHashFilter::EnforcementLevel; +using PrefTrackingStrategy = PrefHashFilter::PrefTrackingStrategy; +using ValueType = PrefHashFilter::ValueType; + const char kAtomicPref[] = "atomic_pref"; const char kAtomicPref2[] = "atomic_pref2"; const char kAtomicPref3[] = "pref3"; @@ -42,41 +46,20 @@ const char kSplitPref[] = "split_pref"; const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = { - {0, - kAtomicPref, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_PERSONAL}, - {1, - kReportOnlyPref, - PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL}, - {2, - kSplitPref, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_SPLIT, - PrefHashFilter::VALUE_IMPERSONAL}, - {3, - kReportOnlySplitPref, - PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::TRACKING_STRATEGY_SPLIT, - PrefHashFilter::VALUE_IMPERSONAL}, - {4, - kAtomicPref2, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL}, - {5, - kAtomicPref3, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL}, - {6, - kAtomicPref4, - PrefHashFilter::ENFORCE_ON_LOAD, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - PrefHashFilter::VALUE_IMPERSONAL}, + {0, kAtomicPref, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL}, + {1, kReportOnlyPref, EnforcementLevel::NO_ENFORCEMENT, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {2, kSplitPref, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::SPLIT, ValueType::IMPERSONAL}, + {3, kReportOnlySplitPref, EnforcementLevel::NO_ENFORCEMENT, + PrefTrackingStrategy::SPLIT, ValueType::IMPERSONAL}, + {4, kAtomicPref2, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {5, kAtomicPref3, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, + {6, kAtomicPref4, EnforcementLevel::ENFORCE_ON_LOAD, + PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL}, }; } // namespace @@ -311,15 +294,13 @@ MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue( const std::string& path, const base::Value* value) const { - return outer_->RecordCheckValue(path, value, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC); + return outer_->RecordCheckValue(path, value, PrefTrackingStrategy::ATOMIC); } void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash( const std::string& path, const base::Value* new_value) { - outer_->RecordStoreHash(path, new_value, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC); + outer_->RecordStoreHash(path, new_value, PrefTrackingStrategy::ATOMIC); } PrefHashStoreTransaction::ValueState @@ -338,14 +319,13 @@ } return outer_->RecordCheckValue(path, initial_split_value, - PrefHashFilter::TRACKING_STRATEGY_SPLIT); + PrefTrackingStrategy::SPLIT); } void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash( const std::string& path, const base::DictionaryValue* new_value) { - outer_->RecordStoreHash(path, new_value, - PrefHashFilter::TRACKING_STRATEGY_SPLIT); + outer_->RecordStoreHash(path, new_value, PrefTrackingStrategy::SPLIT); } bool MockPrefHashStore::MockPrefHashStoreTransaction::HasHash( @@ -719,7 +699,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_value = mock_pref_hash_store_->stored_value(kAtomicPref); ASSERT_EQ(string_value, stored_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value.second); ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); VerifyRecordedReset(false); @@ -779,7 +759,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_value = mock_pref_hash_store_->stored_value(kSplitPref); ASSERT_EQ(dict_value, stored_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value.second); ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); VerifyRecordedReset(false); @@ -835,20 +815,18 @@ MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 = mock_pref_hash_store_->stored_value(kAtomicPref); ASSERT_EQ(int_value1, stored_value_atomic1.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_value_atomic1.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic1.second); ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 = mock_pref_hash_store_->stored_value(kAtomicPref3); ASSERT_EQ(int_value5, stored_value_atomic3.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_value_atomic3.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic3.second); MockPrefHashStore::ValuePtrStrategyPair stored_value_split = mock_pref_hash_store_->stored_value(kSplitPref); ASSERT_EQ(dict_value, stored_value_split.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value_split.second); } TEST_P(PrefHashFilterTest, UnknownNullValue) { @@ -868,13 +846,12 @@ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = mock_pref_hash_store_->stored_value(kAtomicPref); ASSERT_EQ(NULL, stored_atomic_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); ASSERT_EQ(NULL, stored_split_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); // Delegate saw all prefs, two of which had the expected value_state. ASSERT_EQ(arraysize(kTestTrackedPrefs), @@ -887,13 +864,11 @@ const MockValidationDelegateRecord::ValidationEvent* validated_split_pref = mock_validation_delegate_record_->GetEventForPath(kSplitPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, - validated_split_pref->strategy); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, validated_split_pref->strategy); ASSERT_FALSE(validated_split_pref->is_personal); const MockValidationDelegateRecord::ValidationEvent* validated_atomic_pref = mock_validation_delegate_record_->GetEventForPath(kAtomicPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - validated_atomic_pref->strategy); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, validated_atomic_pref->strategy); ASSERT_TRUE(validated_atomic_pref->is_personal); } @@ -915,7 +890,7 @@ mock_pref_hash_store_->SetCheckResult( kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE); // If we are enforcing, expect this to report changes. - DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); + DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD); ASSERT_EQ(arraysize(kTestTrackedPrefs), mock_pref_hash_store_->checked_paths_count()); ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); @@ -934,10 +909,9 @@ mock_pref_hash_store_->stored_value(kAtomicPref); MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); - if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); + if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) { // Ensure the prefs were cleared and the hashes for NULL were restored if // the current enforcement level denies seeding. ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); @@ -1003,8 +977,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = mock_pref_hash_store_->stored_value(kAtomicPref); ASSERT_EQ(string_value, stored_atomic_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); const base::Value* split_value_in_store; ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); @@ -1012,7 +985,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); ASSERT_EQ(dict_value, stored_split_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); } TEST_P(PrefHashFilterTest, InitialValueChanged) { @@ -1040,7 +1013,7 @@ mock_invalid_keys.push_back("c"); mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys); - DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); + DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD); ASSERT_EQ(arraysize(kTestTrackedPrefs), mock_pref_hash_store_->checked_paths_count()); ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); @@ -1050,10 +1023,9 @@ mock_pref_hash_store_->stored_value(kAtomicPref); MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); - if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); + if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) { // Ensure the atomic pref was cleared and the hash for NULL was restored if // the current enforcement level prevents changes. ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); @@ -1121,14 +1093,13 @@ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = mock_pref_hash_store_->stored_value(kAtomicPref); ASSERT_EQ(NULL, stored_atomic_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL)); MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); ASSERT_EQ(NULL, stored_split_value.first); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); } TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) { @@ -1170,8 +1141,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = mock_pref_hash_store_->stored_value(kAtomicPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, - stored_atomic_value.second); + ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second); const base::Value* atomic_value_in_store; ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store)); ASSERT_EQ(string_value, atomic_value_in_store); @@ -1179,7 +1149,7 @@ MockPrefHashStore::ValuePtrStrategyPair stored_split_value = mock_pref_hash_store_->stored_value(kSplitPref); - ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_split_value.second); + ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second); const base::Value* split_value_in_store; ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); ASSERT_EQ(dict_value, split_value_in_store); @@ -1214,7 +1184,7 @@ mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref, PrefHashStoreTransaction::CHANGED); - DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); + DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD); // All prefs should be checked and a new hash should be stored for each tested // pref. ASSERT_EQ(arraysize(kTestTrackedPrefs), @@ -1241,7 +1211,7 @@ mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first); // All other prefs should have been reset if the enforcement level allows it. - if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { + if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) { ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref2, NULL)); ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first); @@ -1393,5 +1363,5 @@ INSTANTIATE_TEST_CASE_P(PrefHashFilterTestInstance, PrefHashFilterTest, - testing::Values(PrefHashFilter::NO_ENFORCEMENT, - PrefHashFilter::ENFORCE_ON_LOAD)); + testing::Values(EnforcementLevel::NO_ENFORCEMENT, + EnforcementLevel::ENFORCE_ON_LOAD));
diff --git a/components/user_prefs/tracked/tracked_preference_helper.cc b/components/user_prefs/tracked/tracked_preference_helper.cc index fb36a2a..b0415c4 100644 --- a/components/user_prefs/tracked/tracked_preference_helper.cc +++ b/components/user_prefs/tracked/tracked_preference_helper.cc
@@ -18,9 +18,9 @@ : pref_path_(pref_path), reporting_id_(reporting_id), reporting_ids_count_(reporting_ids_count), - enforce_(enforcement_level == PrefHashFilter::ENFORCE_ON_LOAD), - personal_(value_type == PrefHashFilter::VALUE_PERSONAL) { -} + enforce_(enforcement_level == + PrefHashFilter::EnforcementLevel::ENFORCE_ON_LOAD), + personal_(value_type == PrefHashFilter::ValueType::PERSONAL) {} TrackedPreferenceHelper::ResetAction TrackedPreferenceHelper::GetAction( PrefHashStoreTransaction::ValueState value_state) const {
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index f226027..dfc904bb 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc
@@ -311,10 +311,6 @@ child_process_host_->ForceShutdown(); } -void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) { - child_process_->SetProcessBackgrounded(backgrounded); -} - void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) { child_process_host_->AddFilter(filter->GetFilter()); }
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h index 3c78e6a..bb654dbf 100644 --- a/content/browser/browser_child_process_host_impl.h +++ b/content/browser/browser_child_process_host_impl.h
@@ -101,9 +101,6 @@ // Removes this host from the host list. Calls ChildProcessHost::ForceShutdown void ForceShutdown(); - // Callers can reduce the BrowserChildProcess' priority. - void SetBackgrounded(bool backgrounded); - // Adds an IPC message filter. void AddFilter(BrowserMessageFilter* filter);
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index 7b85e54..0ea3dd16 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -896,24 +896,20 @@ void BrowserPluginGuest::OnImeSetComposition( int browser_plugin_instance_id, - const std::string& text, - const std::vector<blink::WebCompositionUnderline>& underlines, - int selection_start, - int selection_end) { - Send(new InputMsg_ImeSetComposition(routing_id(), - base::UTF8ToUTF16(text), underlines, - gfx::Range::InvalidRange(), - selection_start, selection_end)); + const BrowserPluginHostMsg_SetComposition_Params& params) { + Send(new InputMsg_ImeSetComposition( + routing_id(), params.text, params.underlines, params.replacement_range, + params.selection_start, params.selection_end)); } void BrowserPluginGuest::OnImeCommitText( int browser_plugin_instance_id, - const std::string& text, + const base::string16& text, const std::vector<blink::WebCompositionUnderline>& underlines, + const gfx::Range& replacement_range, int relative_cursor_pos) { - Send(new InputMsg_ImeCommitText(routing_id(), base::UTF8ToUTF16(text), - underlines, gfx::Range::InvalidRange(), - relative_cursor_pos)); + Send(new InputMsg_ImeCommitText(routing_id(), text, underlines, + replacement_range, relative_cursor_pos)); } void BrowserPluginGuest::OnImeFinishComposingText(bool keep_selection) {
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h index f1218cd..fedd4a7 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.h +++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -45,6 +45,7 @@ #include "ui/gfx/geometry/rect.h" struct BrowserPluginHostMsg_Attach_Params; +struct BrowserPluginHostMsg_SetComposition_Params; #if defined(OS_MACOSX) struct FrameHostMsg_ShowPopup_Params; @@ -342,14 +343,12 @@ void OnTextInputStateChanged(const TextInputState& params); void OnImeSetComposition( int instance_id, - const std::string& text, - const std::vector<blink::WebCompositionUnderline>& underlines, - int selection_start, - int selection_end); + const BrowserPluginHostMsg_SetComposition_Params& params); void OnImeCommitText( int instance_id, - const std::string& text, + const base::string16& text, const std::vector<blink::WebCompositionUnderline>& underlines, + const gfx::Range& replacement_range, int relative_cursor_pos); void OnImeFinishComposingText(bool keep_selection); void OnExtendSelectionAndDelete(int instance_id, int before, int after);
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc index 11a508b..de70cc65 100644 --- a/content/browser/devtools/protocol/tracing_handler.cc +++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -269,7 +269,7 @@ size_t approximate_event_count) { // TODO(crbug426117): remove set_value once all clients have switched to // the new interface of the event. - frontend_->BufferUsage(percent_full, percent_full, approximate_event_count); + frontend_->BufferUsage(percent_full, approximate_event_count, percent_full); } void TracingHandler::OnCategoriesReceived(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 29517e0..77fdcb7b 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -376,6 +376,9 @@ SetUpMojoIfNeeded(); swapout_event_monitor_timeout_.reset(new TimeoutMonitor(base::Bind( &RenderFrameHostImpl::OnSwappedOut, weak_ptr_factory_.GetWeakPtr()))); + beforeunload_timeout_.reset( + new TimeoutMonitor(base::Bind(&RenderFrameHostImpl::BeforeUnloadTimeout, + weak_ptr_factory_.GetWeakPtr()))); if (widget_routing_id != MSG_ROUTING_NONE) { // TODO(avi): Once RenderViewHostImpl has-a RenderWidgetHostImpl, the main @@ -1481,8 +1484,7 @@ } // Resets beforeunload waiting state. is_waiting_for_beforeunload_ack_ = false; - render_view_host_->GetWidget()->decrement_in_flight_event_count(); - render_view_host_->GetWidget()->StopHangMonitorTimeout(); + beforeunload_timeout_->Stop(); send_before_unload_start_time_ = base::TimeTicks(); // PlzNavigate: if the ACK is for a navigation, send it to the Navigator to @@ -1704,6 +1706,13 @@ // shouldn't process input events. GetProcess()->SetIgnoreInputEvents(true); render_view_host_->GetWidget()->StopHangMonitorTimeout(); + + // The beforeunload dialog for this frame may have been triggered by a + // browser-side request to this frame or a frame up in the frame hierarchy. + // Stop any timers that are waiting. + for (RenderFrameHostImpl* frame = this; frame; frame = frame->GetParent()) + frame->beforeunload_timeout_->Stop(); + delegate_->RunBeforeUnloadConfirm(this, is_reload, reply_msg); } @@ -2420,8 +2429,7 @@ // navigations to be ignored in OnDidCommitProvisionalLoad. if (is_waiting_for_beforeunload_ack_) { is_waiting_for_beforeunload_ack_ = false; - render_view_host_->GetWidget()->decrement_in_flight_event_count(); - render_view_host_->GetWidget()->StopHangMonitorTimeout(); + beforeunload_timeout_->Stop(); } send_before_unload_start_time_ = base::TimeTicks(); render_view_host_->is_waiting_for_close_ack_ = false; @@ -2567,12 +2575,8 @@ // reply from the dialog. SimulateBeforeUnloadAck(); } else { - // Increment the in-flight event count, to ensure that input events won't - // cancel the timeout timer. - render_view_host_->GetWidget()->increment_in_flight_event_count(); - render_view_host_->GetWidget()->StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS), - blink::WebInputEvent::Undefined); + beforeunload_timeout_->Start( + TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS)); send_before_unload_start_time_ = base::TimeTicks::Now(); Send(new FrameMsg_BeforeUnload(routing_id_, is_reload)); } @@ -2637,33 +2641,27 @@ IPC::Message* reply_msg, bool success, const base::string16& user_input, - bool is_before_unload_dialog, bool dialog_was_suppressed) { GetProcess()->SetIgnoreInputEvents(false); - // If we are executing as part of beforeunload event handling, we don't - // want to use the regular hung_renderer_delay_ms_ if the user has agreed to - // leave the current page. In this case, use the regular timeout value used - // during the beforeunload handling. - if (is_before_unload_dialog) { - render_view_host_->GetWidget()->StartHangMonitorTimeout( - success - ? TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS) - : render_view_host_->GetWidget()->hung_renderer_delay(), - blink::WebInputEvent::Undefined); - } - SendJavaScriptDialogReply(reply_msg, success, user_input); - // If we are waiting for a beforeunload ack and the user has suppressed - // messages, kill the tab immediately; a page that's spamming alerts in - // onbeforeunload is presumably malicious, so there's no point in continuing - // to run its script and dragging out the process. This must be done after - // sending the reply since RenderView can't close correctly while waiting for - // a response. - if (is_before_unload_dialog && dialog_was_suppressed) { - render_view_host_->GetWidget()->delegate()->RendererUnresponsive( - render_view_host_->GetWidget()); + // If executing as part of beforeunload event handling, there may have been + // timers stopped in this frame or a frame up in the frame hierarchy. Restart + // any timers that were stopped in OnRunBeforeUnloadConfirm(). + for (RenderFrameHostImpl* frame = this; frame; frame = frame->GetParent()) { + if (frame->is_waiting_for_beforeunload_ack_) { + // If we are waiting for a beforeunload ack and the user has suppressed + // messages, kill the tab immediately. A page that's spamming is + // presumably malicious, so there's no point in continuing to run its + // script and dragging out the process. + if (dialog_was_suppressed) { + frame->SimulateBeforeUnloadAck(); + } else { + frame->beforeunload_timeout_->Start( + TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS)); + } + } } } @@ -3490,6 +3488,13 @@ entry_id_for_data_nav, false); // started_from_context_menu } +void RenderFrameHostImpl::BeforeUnloadTimeout() { + if (render_view_host_->GetDelegate()->ShouldIgnoreUnresponsiveRenderer()) + return; + + SimulateBeforeUnloadAck(); +} + #if defined(OS_ANDROID) base::android::ScopedJavaLocalRef<jobject> RenderFrameHostImpl::GetJavaRenderFrameHost() {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 4b10798..b5c7fe6 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -459,7 +459,6 @@ void JavaScriptDialogClosed(IPC::Message* reply_msg, bool success, const base::string16& user_input, - bool is_before_unload_dialog, bool dialog_was_suppressed); // Get the accessibility mode from the delegate and Send a message to the @@ -889,6 +888,9 @@ std::unique_ptr<NavigationHandleImpl> TakeNavigationHandleForCommit( const FrameHostMsg_DidCommitProvisionalLoad_Params& params); + // Called by |beforeunload_timeout_| when the beforeunload timeout fires. + void BeforeUnloadTimeout(); + // For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a // refcount that calls Shutdown when it reaches zero. This allows each // RenderFrameHostManager to just care about RenderFrameHosts, while ensuring @@ -993,6 +995,11 @@ // PlzNavigate: all navigations require a beforeUnload ACK. bool unload_ack_is_for_navigation_; + // The timeout monitor that runs from when the beforeunload is started in + // DispatchBeforeUnload() until either the render process ACKs it with an IPC + // to OnBeforeUnloadACK(), or until the timeout triggers. + std::unique_ptr<TimeoutMonitor> beforeunload_timeout_; + // Indicates whether this RenderFrameHost is in the process of loading a // document or not. bool is_loading_;
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc index 6547788..5f46755 100644 --- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -6,9 +6,12 @@ #include "base/macros.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/frame_messages.h" +#include "content/public/browser/javascript_dialog_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_client.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" @@ -156,4 +159,126 @@ SetBrowserClientForTesting(old_client); } +namespace { + +class TestJavaScriptDialogManager : public JavaScriptDialogManager, + public WebContentsDelegate { + public: + TestJavaScriptDialogManager() : message_loop_runner_(new MessageLoopRunner) {} + ~TestJavaScriptDialogManager() override {} + + void Wait() { + message_loop_runner_->Run(); + message_loop_runner_ = new MessageLoopRunner; + } + + DialogClosedCallback& callback() { return callback_; } + + // WebContentsDelegate + + JavaScriptDialogManager* GetJavaScriptDialogManager( + WebContents* source) override { + return this; + } + + // JavaScriptDialogManager + + void RunJavaScriptDialog(WebContents* web_contents, + const GURL& origin_url, + JavaScriptDialogType dialog_type, + const base::string16& message_text, + const base::string16& default_prompt_text, + const DialogClosedCallback& callback, + bool* did_suppress_message) override {} + + void RunBeforeUnloadDialog(WebContents* web_contents, + bool is_reload, + const DialogClosedCallback& callback) override { + callback_ = callback; + message_loop_runner_->Quit(); + } + + bool HandleJavaScriptDialog(WebContents* web_contents, + bool accept, + const base::string16* prompt_override) override { + return true; + } + + void CancelDialogs(WebContents* web_contents, bool reset_state) override {} + + private: + DialogClosedCallback callback_; + + // The MessageLoopRunner used to spin the message loop. + scoped_refptr<MessageLoopRunner> message_loop_runner_; + + DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager); +}; + +class DropBeforeUnloadACKFilter : public BrowserMessageFilter { + public: + DropBeforeUnloadACKFilter() : BrowserMessageFilter(FrameMsgStart) {} + + protected: + ~DropBeforeUnloadACKFilter() override {} + + private: + // BrowserMessageFilter: + bool OnMessageReceived(const IPC::Message& message) override { + return message.type() == FrameHostMsg_BeforeUnload_ACK::ID; + } + + DISALLOW_COPY_AND_ASSIGN(DropBeforeUnloadACKFilter); +}; + +} // namespace + +// Tests that a beforeunload dialog in an iframe doesn't stop the beforeunload +// timer of a parent frame. +IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, + IframeBeforeUnloadParentHang) { + WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); + TestJavaScriptDialogManager dialog_manager; + wc->SetDelegate(&dialog_manager); + + EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); + // Make an iframe with a beforeunload handler. + std::string script = + "var iframe = document.createElement('iframe');" + "document.body.appendChild(iframe);" + "iframe.contentWindow.onbeforeunload=function(e){return 'x'};"; + EXPECT_TRUE(content::ExecuteScript(wc, script)); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + + // Force a process switch by going to a privileged page. The beforeunload + // timer will be started on the top-level frame but will be paused while the + // beforeunload dialog is shown by the subframe. + GURL web_ui_page(std::string(kChromeUIScheme) + "://" + + std::string(kChromeUIGpuHost)); + shell()->LoadURL(web_ui_page); + dialog_manager.Wait(); + + RenderFrameHostImpl* main_frame = + static_cast<RenderFrameHostImpl*>(wc->GetMainFrame()); + EXPECT_TRUE(main_frame->is_waiting_for_beforeunload_ack()); + + // Set up a filter to make sure that when the dialog is answered below and the + // renderer sends the beforeunload ACK, it gets... ahem... lost. + scoped_refptr<DropBeforeUnloadACKFilter> filter = + new DropBeforeUnloadACKFilter(); + main_frame->GetProcess()->AddFilter(filter.get()); + + // Answer the dialog. + dialog_manager.callback().Run(true, base::string16()); + + // There will be no beforeunload ACK, so if the beforeunload ACK timer isn't + // functioning then the navigation will hang forever and this test will time + // out. If this waiting for the load stop works, this test won't time out. + EXPECT_TRUE(WaitForLoadStop(wc)); + EXPECT_EQ(web_ui_page, wc->GetLastCommittedURL()); + + wc->SetDelegate(nullptr); + wc->SetJavaScriptDialogManagerForTesting(nullptr); +} + } // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index e61eb44b..bb52257 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -2134,11 +2134,16 @@ "FrameTreeNode id", frame_tree_node_->frame_tree_node_id()); DCHECK(pending_render_frame_host_ || speculative_render_frame_host_); + bool is_main_frame = frame_tree_node_->IsMainFrame(); + // First check whether we're going to want to focus the location bar after // this commit. We do this now because the navigation hasn't formally // committed yet, so if we've already cleared the pending WebUI the call chain - // this triggers won't be able to figure out what's going on. - bool will_focus_location_bar = delegate_->FocusLocationBarByDefault(); + // this triggers won't be able to figure out what's going on. Note that + // subframe commits should not be allowed to steal focus from the main frame + // by focusing the location bar (see https://crbug.com/700124). + bool will_focus_location_bar = + is_main_frame && delegate_->FocusLocationBarByDefault(); // Remember if the page was focused so we can focus the new renderer in // that case. @@ -2146,8 +2151,6 @@ render_frame_host_->GetView() && render_frame_host_->GetView()->HasFocus(); - bool is_main_frame = frame_tree_node_->IsMainFrame(); - // While the old frame is still current, remove its children from the tree. frame_tree_node_->ResetForNewProcess();
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc index 772aad36..938e3ba 100644 --- a/content/browser/frame_host/render_widget_host_view_guest.cc +++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -84,7 +84,8 @@ : RenderWidgetHostViewChildFrame(widget_host), // |guest| is NULL during test. guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()), - platform_view_(platform_view) { + platform_view_(platform_view), + should_forward_text_selection_(false) { gfx::NativeView view = GetNativeView(); if (view) UpdateScreenInfo(view); @@ -372,6 +373,9 @@ return; // Forward the information to embedding RWHV. rwhv->TextInputStateChanged(params); + + should_forward_text_selection_ = + (params.type != ui::TEXT_INPUT_TYPE_NONE) && guest_ && guest_->focused(); } void RenderWidgetHostViewGuest::ImeCancelComposition() { @@ -409,7 +413,11 @@ void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text, size_t offset, const gfx::Range& range) { - platform_view_->SelectionChanged(text, offset, range); + RenderWidgetHostViewBase* view = should_forward_text_selection_ + ? GetOwnerRenderWidgetHostView() + : platform_view_.get(); + if (view) + view->SelectionChanged(text, offset, range); } void RenderWidgetHostViewGuest::SelectionBoundsChanged(
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h index e5c20e6..8371712 100644 --- a/content/browser/frame_host/render_widget_host_view_guest.h +++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -161,6 +161,12 @@ // RenderWidgetHostViewGuest mostly only cares about stuff related to // compositing, the rest are directly forwarded to this |platform_view_|. base::WeakPtr<RenderWidgetHostViewBase> platform_view_; + + // When true the guest will forward its selection updates to the owner RWHV. + // The guest may forward its updates only when there is an ongoing IME + // session. + bool should_forward_text_selection_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewGuest); };
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index a835ff8..ae0025e 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -1153,9 +1153,8 @@ crashed_before_ = true; last_gpu_crash_time = current_time; - if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount && - !disable_crash_limit) || - !initialized_) { + if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount || !initialized_) && + !disable_crash_limit) { #if !defined(OS_CHROMEOS) // The GPU process is too unstable to use. Disable it for current // session.
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc index 20a9bf1..1c4fc78 100644 --- a/content/browser/loader/mojo_async_resource_handler.cc +++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -121,7 +121,7 @@ : ResourceHandler(request), rdh_(rdh), binding_(this, std::move(mojo_request)), - handle_watcher_(FROM_HERE), + handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL), url_loader_client_(std::move(url_loader_client)), weak_factory_(this) { DCHECK(url_loader_client_); @@ -245,9 +245,10 @@ response_body_consumer_handle_ = std::move(data_pipe.consumer_handle); shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle)); - handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, + handle_watcher_.Watch(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, base::Bind(&MojoAsyncResourceHandler::OnWritable, base::Unretained(this))); + handle_watcher_.ArmOrNotify(); bool defer = false; scoped_refptr<net::IOBufferWithSize> buffer; @@ -388,11 +389,16 @@ shared_writer_->writer(), data, available, MOJO_WRITE_DATA_FLAG_NONE); if (result == MOJO_RESULT_OK) *available = std::min(*available, static_cast<uint32_t>(kMaxChunkSize)); + else if (result == MOJO_RESULT_SHOULD_WAIT) + handle_watcher_.ArmOrNotify(); return result; } MojoResult MojoAsyncResourceHandler::EndWrite(uint32_t written) { - return mojo::EndWriteDataRaw(shared_writer_->writer(), written); + MojoResult result = mojo::EndWriteDataRaw(shared_writer_->writer(), written); + if (result == MOJO_RESULT_OK) + handle_watcher_.ArmOrNotify(); + return result; } net::IOBufferWithSize* MojoAsyncResourceHandler::GetResponseMetadata(
diff --git a/content/browser/loader/mojo_async_resource_handler.h b/content/browser/loader/mojo_async_resource_handler.h index b8cd1e5..ce84d64 100644 --- a/content/browser/loader/mojo_async_resource_handler.h +++ b/content/browser/loader/mojo_async_resource_handler.h
@@ -20,7 +20,7 @@ #include "content/public/common/resource_type.h" #include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "net/base/io_buffer.h" #include "net/base/request_priority.h" @@ -137,7 +137,7 @@ base::TimeTicks response_started_ticks_; int64_t reported_total_received_bytes_ = 0; - mojo::Watcher handle_watcher_; + mojo::SimpleWatcher handle_watcher_; std::unique_ptr<mojom::URLLoader> url_loader_; mojom::URLLoaderClientPtr url_loader_client_; scoped_refptr<net::IOBufferWithSize> buffer_;
diff --git a/content/browser/loader/reload_cache_control_browsertest.cc b/content/browser/loader/reload_cache_control_browsertest.cc index 7d7a6818..05e8481 100644 --- a/content/browser/loader/reload_cache_control_browsertest.cc +++ b/content/browser/loader/reload_cache_control_browsertest.cc
@@ -27,8 +27,16 @@ using net::test_server::HttpRequest; using net::test_server::HttpResponse; -const char kReloadTestPath[] = "/loader/reload.html"; +const char kReloadTestPath[] = "/loader/reload_test.html"; +const char kReloadFramePath[] = "/loader/simple_frame.html"; const char kReloadImagePath[] = "/loader/empty16x16.png"; +// The test page should request resources as the content structure is described +// below. Reload and the same page navigation will affect only the top frame +// resource, reload_test.html. But bypassing reload will affect all resources. +// +- reload_test.html +// +- empty16x16.png +// +- simple_frame.html +// +- empty16x16.png const char kNoCacheControl[] = ""; const char kMaxAgeCacheControl[] = "max-age=0"; @@ -80,6 +88,7 @@ DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlBrowserTest); }; +// Test if reload issues requests with proper cache control flags. IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NormalReload) { GURL url(embedded_test_server()->GetURL(kReloadTestPath)); @@ -88,16 +97,25 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(4UL, request_log_.size()); + ASSERT_EQ(8UL, request_log_.size()); EXPECT_EQ(kReloadTestPath, request_log_[0].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[0].cache_control); EXPECT_EQ(kReloadImagePath, request_log_[1].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[1].cache_control); - - EXPECT_EQ(kReloadTestPath, request_log_[2].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[2].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[2].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[2].cache_control); EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[4].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[5].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[6].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[6].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[7].cache_control); } shell()->ShowDevTools(); @@ -105,11 +123,17 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(6UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[4].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); - EXPECT_EQ(kNoCacheControl, request_log_[5].cache_control); + ASSERT_EQ(12UL, request_log_.size()); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[8].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[8].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[9].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[9].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[10].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[10].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[11].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[11].cache_control); } shell()->CloseDevTools(); @@ -117,14 +141,21 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(8UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[6].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[6].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); - EXPECT_EQ(kNoCacheControl, request_log_[7].cache_control); + ASSERT_EQ(16UL, request_log_.size()); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[12].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[12].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[13].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[13].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[14].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[14].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[15].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[15].cache_control); } } +// Test if bypassing reload issues requests with proper cache control flags. IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, BypassingReload) { GURL url(embedded_test_server()->GetURL(kReloadTestPath)); @@ -133,16 +164,25 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(4UL, request_log_.size()); + ASSERT_EQ(8UL, request_log_.size()); EXPECT_EQ(kReloadTestPath, request_log_[0].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[0].cache_control); EXPECT_EQ(kReloadImagePath, request_log_[1].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[1].cache_control); - - EXPECT_EQ(kReloadTestPath, request_log_[2].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[2].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[2].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[2].cache_control); EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[3].cache_control); + EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control); + + // Only the top main resource should be requested with kNoCacheCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[4].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[5].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[6].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[6].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[7].cache_control); } shell()->ShowDevTools(); @@ -150,11 +190,17 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(6UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[4].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[5].cache_control); + ASSERT_EQ(12UL, request_log_.size()); + + // All resources should be requested with kNoCacheCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[8].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[8].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[9].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[9].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[10].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[10].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[11].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[11].cache_control); } shell()->CloseDevTools(); @@ -162,14 +208,22 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(8UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[6].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[6].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); - EXPECT_EQ(kNoCacheCacheControl, request_log_[7].cache_control); + ASSERT_EQ(16UL, request_log_.size()); + + // All resources should be requested with kNoCacheCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[12].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[12].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[13].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[13].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[14].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[14].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[15].relative_url); + EXPECT_EQ(kNoCacheCacheControl, request_log_[15].cache_control); } } +// Test if the same page navigation issues requests with proper cache control +// flags. IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NavigateToSame) { GURL url(embedded_test_server()->GetURL(kReloadTestPath)); @@ -179,11 +233,15 @@ // The first navigation is just a normal load. { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(4UL, request_log_.size()); + ASSERT_EQ(8UL, request_log_.size()); EXPECT_EQ(kReloadTestPath, request_log_[0].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[0].cache_control); EXPECT_EQ(kReloadImagePath, request_log_[1].relative_url); EXPECT_EQ(kNoCacheControl, request_log_[1].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[2].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control); } // TODO(crbug.com/671545): This test does not work correctly if browser-side @@ -196,10 +254,16 @@ // for others. { base::AutoLock lock(request_log_lock_); - EXPECT_EQ(kReloadTestPath, request_log_[2].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[2].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url); - EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[4].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[5].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[6].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[6].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[7].cache_control); } shell()->ShowDevTools(); @@ -207,11 +271,17 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(6UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[4].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[4].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[5].relative_url); - EXPECT_EQ(kNoCacheControl, request_log_[5].cache_control); + ASSERT_EQ(12UL, request_log_.size()); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[8].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[8].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[9].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[9].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[10].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[10].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[11].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[11].cache_control); } shell()->CloseDevTools(); @@ -219,11 +289,17 @@ { base::AutoLock lock(request_log_lock_); - ASSERT_EQ(8UL, request_log_.size()); - EXPECT_EQ(kReloadTestPath, request_log_[6].relative_url); - EXPECT_EQ(kMaxAgeCacheControl, request_log_[6].cache_control); - EXPECT_EQ(kReloadImagePath, request_log_[7].relative_url); - EXPECT_EQ(kNoCacheControl, request_log_[7].cache_control); + ASSERT_EQ(16UL, request_log_.size()); + + // Only the top main resource should be requested with kMaxAgeCacheControl. + EXPECT_EQ(kReloadTestPath, request_log_[12].relative_url); + EXPECT_EQ(kMaxAgeCacheControl, request_log_[12].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[13].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[13].cache_control); + EXPECT_EQ(kReloadFramePath, request_log_[14].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[14].cache_control); + EXPECT_EQ(kReloadImagePath, request_log_[15].relative_url); + EXPECT_EQ(kNoCacheControl, request_log_[15].cache_control); } }
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 752c352e..27f9a45f 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -316,6 +316,15 @@ params->page_zoom_level = delegate_->GetPendingPageZoomLevel(); params->image_decode_color_space = gfx::ICCProfile::FromBestMonitor(); + // Pretend that HDR displays are sRGB so that we do not have inconsistent + // coloring. + // TODO(ccameron): Disable this once color correct rasterization is functional + // https://crbug.com/701942 + if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR)) { + gfx::ColorSpace::CreateSRGB().GetICCProfile( + ¶ms->image_decode_color_space); + } + GetWidget()->GetResizeParams(¶ms->initial_size); GetWidget()->SetInitialRenderSizeParams(params->initial_size);
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index e054001..175f1687 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -82,6 +82,7 @@ #include "storage/browser/fileapi/isolated_context.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/base/ui_base_switches.h" #include "ui/events/blink/web_input_event_traits.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -667,6 +668,16 @@ *resize_params = ResizeParams(); GetScreenInfo(&resize_params->screen_info); + + // Pretend that HDR displays are sRGB so that we do not have inconsistent + // coloring. + // TODO(ccameron): Disable this once color correct rasterization is functional + // https://crbug.com/701942 + if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR)) { + gfx::ColorSpace::CreateSRGB().GetICCProfile( + &resize_params->screen_info.icc_profile); + } + if (delegate_) { resize_params->is_fullscreen_granted = delegate_->IsFullscreenForCurrentTab(); @@ -2106,14 +2117,15 @@ void RenderWidgetHostImpl::IncrementInFlightEventCount( blink::WebInputEvent::Type event_type) { - increment_in_flight_event_count(); + ++in_flight_event_count_; if (!is_hidden_) StartHangMonitorTimeout(hung_renderer_delay_, event_type); } void RenderWidgetHostImpl::DecrementInFlightEventCount( InputEventAckSource ack_source) { - if (decrement_in_flight_event_count() <= 0) { + --in_flight_event_count_; + if (in_flight_event_count_ <= 0) { // Cancel pending hung renderer checks since the renderer is responsive. StopHangMonitorTimeout(); } else {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 3ea94419..e98b0e4 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -553,14 +553,6 @@ uint32_t offset, const gfx::Range& range); - // Expose increment/decrement of the in-flight event count, so - // RenderViewHostImpl can account for in-flight beforeunload/unload events. - int increment_in_flight_event_count() { return ++in_flight_event_count_; } - int decrement_in_flight_event_count() { - DCHECK_GT(in_flight_event_count_, 0); - return --in_flight_event_count_; - } - size_t in_flight_event_count() const { return in_flight_event_count_; } blink::WebInputEvent::Type hang_monitor_event_type() const { return hang_monitor_event_type_;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 6266020..0cb516b 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1431,6 +1431,10 @@ cc::CompositorFrame frame) { TRACE_EVENT0("browser", "RenderWidgetHostViewMac::OnSwapCompositorFrame"); + // Override the compositor background color. See RenderWidgetHostViewAura + // for more details. + SetBackgroundColor(frame.metadata.root_background_color); + last_scroll_offset_ = frame.metadata.root_scroll_offset; page_at_minimum_scale_ =
diff --git a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc index db5c128..6048190 100644 --- a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc +++ b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -15,10 +15,10 @@ #include "base/atomic_sequence_num.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/run_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" #include "content/browser/shared_worker/shared_worker_message_filter.h" #include "content/browser/shared_worker/worker_storage_partition.h" #include "content/common/view_messages.h" @@ -112,11 +112,9 @@ static const int kRenderFrameRouteIDs[] = {300, 301, 302}; void BlockingReadFromMessagePort(MessagePort port, base::string16* message) { - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - port.SetCallback( - base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); - event.Wait(); + base::RunLoop run_loop; + port.SetCallback(run_loop.QuitClosure()); + run_loop.Run(); std::vector<MessagePort> should_be_empty; EXPECT_TRUE(port.GetMessage(message, &should_be_empty));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index a8e41e5..d8bdf2f 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4226,9 +4226,7 @@ delegate_->ShouldSuppressDialogs(this) || !delegate_->GetJavaScriptDialogManager(this); if (suppress_this_message) { - rfhi->JavaScriptDialogClosed(reply_msg, true, base::string16(), - /*is_before_unload_dialog=*/true, - /*dialog_was_suppressed=*/true); + rfhi->JavaScriptDialogClosed(reply_msg, true, base::string16(), true); return; } @@ -4846,16 +4844,6 @@ if (ShouldIgnoreUnresponsiveRenderer()) return; - RenderFrameHostImpl* rfhi = - static_cast<RenderFrameHostImpl*>(GetRenderViewHost()->GetMainFrame()); - if (rfhi->is_waiting_for_beforeunload_ack()) { - // If the hang is in the beforeunload handler, pretend the beforeunload - // listeners have all fired and allow the delegate to continue closing; - // the user will not have the option of cancelling the close. - rfhi->SimulateBeforeUnloadAck(); - return; - } - if (!GetRenderViewHost() || !GetRenderViewHost()->IsRenderViewLive()) return; @@ -5117,7 +5105,6 @@ if (rfh) { rfh->JavaScriptDialogClosed(reply_msg, success, user_input, - is_showing_before_unload_dialog_, dialog_was_suppressed); } else { // Don't leak the sync IPC reply if the RFH or process is gone.
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index be6e06b..4ea1053 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -843,6 +843,8 @@ CrossSiteIframeAccessibility); FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest, JavaScriptDialogsInMainAndSubframes); + FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, + IframeBeforeUnloadParentHang); // So |find_request_manager_| can be accessed for testing. friend class FindRequestManagerTest;
diff --git a/content/child/url_response_body_consumer.cc b/content/child/url_response_body_consumer.cc index a51b4f7..1095ea15c 100644 --- a/content/child/url_response_body_consumer.cc +++ b/content/child/url_response_body_consumer.cc
@@ -48,15 +48,15 @@ : request_id_(request_id), resource_dispatcher_(resource_dispatcher), handle_(std::move(handle)), - handle_watcher_(FROM_HERE, task_runner), + handle_watcher_(FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::MANUAL, + task_runner), task_runner_(task_runner), has_seen_end_of_data_(!handle_.is_valid()) { - handle_watcher_.Start( + handle_watcher_.Watch( handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&URLResponseBodyConsumer::OnReadable, base::Unretained(this))); - task_runner_->PostTask( - FROM_HERE, base::Bind(&URLResponseBodyConsumer::OnReadable, AsWeakPtr(), - MOJO_RESULT_OK)); + handle_watcher_.ArmOrNotify(); } URLResponseBodyConsumer::~URLResponseBodyConsumer() {} @@ -91,9 +91,7 @@ if (is_in_on_readable_) return; - task_runner_->PostTask( - FROM_HERE, base::Bind(&URLResponseBodyConsumer::OnReadable, AsWeakPtr(), - MOJO_RESULT_OK)); + handle_watcher_.ArmOrNotify(); } void URLResponseBodyConsumer::OnReadable(MojoResult unused) { @@ -112,7 +110,11 @@ uint32_t available = 0; MojoResult result = mojo::BeginReadDataRaw( handle_.get(), &buffer, &available, MOJO_READ_DATA_FLAG_NONE); - if (result == MOJO_RESULT_SHOULD_WAIT || result == MOJO_RESULT_BUSY) + if (result == MOJO_RESULT_SHOULD_WAIT) { + handle_watcher_.ArmOrNotify(); + return; + } + if (result == MOJO_RESULT_BUSY) return; if (result == MOJO_RESULT_FAILED_PRECONDITION) { has_seen_end_of_data_ = true; @@ -134,9 +136,7 @@ // to the next task. result = mojo::EndReadDataRaw(handle_.get(), 0); DCHECK_EQ(result, MOJO_RESULT_OK); - task_runner_->PostTask(FROM_HERE, - base::Bind(&URLResponseBodyConsumer::OnReadable, - AsWeakPtr(), MOJO_RESULT_OK)); + handle_watcher_.ArmOrNotify(); return; } num_bytes_consumed += available;
diff --git a/content/child/url_response_body_consumer.h b/content/child/url_response_body_consumer.h index 1c33aaa..ce6b88a9 100644 --- a/content/child/url_response_body_consumer.h +++ b/content/child/url_response_body_consumer.h
@@ -18,7 +18,7 @@ #include "content/common/content_export.h" #include "content/common/url_loader.mojom.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace content { @@ -71,7 +71,7 @@ const int request_id_; ResourceDispatcher* resource_dispatcher_; mojo::ScopedDataPipeConsumerHandle handle_; - mojo::Watcher handle_watcher_; + mojo::SimpleWatcher handle_watcher_; ResourceRequestCompletionStatus completion_status_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/content/child/web_data_consumer_handle_impl.cc b/content/child/web_data_consumer_handle_impl.cc index f81221d8..b40f479 100644 --- a/content/child/web_data_consumer_handle_impl.cc +++ b/content/child/web_data_consumer_handle_impl.cc
@@ -37,7 +37,9 @@ WebDataConsumerHandleImpl::ReaderImpl::ReaderImpl( scoped_refptr<Context> context, Client* client) - : context_(context), handle_watcher_(FROM_HERE), client_(client) { + : context_(context), + handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC), + client_(client) { if (client_) StartWatching(); } @@ -130,7 +132,7 @@ } void WebDataConsumerHandleImpl::ReaderImpl::StartWatching() { - handle_watcher_.Start( + handle_watcher_.Watch( context_->handle().get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&ReaderImpl::OnHandleGotReadable, base::Unretained(this))); }
diff --git a/content/child/web_data_consumer_handle_impl.h b/content/child/web_data_consumer_handle_impl.h index fb814a2..16e61d26 100644 --- a/content/child/web_data_consumer_handle_impl.h +++ b/content/child/web_data_consumer_handle_impl.h
@@ -11,7 +11,7 @@ #include "content/common/content_export.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "third_party/WebKit/public/platform/WebDataConsumerHandle.h" namespace content { @@ -41,7 +41,7 @@ void OnHandleGotReadable(MojoResult); scoped_refptr<Context> context_; - mojo::Watcher handle_watcher_; + mojo::SimpleWatcher handle_watcher_; Client* client_; DISALLOW_COPY_AND_ASSIGN(ReaderImpl);
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 4a7001d..38664d97 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -306,7 +306,6 @@ "sandbox_win.cc", "sandbox_win.h", "savable_subframe.h", - "screen_orientation_messages.h", "send_zygote_child_ping_linux.cc", "service_manager/embedded_service_runner.cc", "service_manager/embedded_service_runner.h",
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h index 8c4ebd94..b4e635e9 100644 --- a/content/common/browser_plugin/browser_plugin_messages.h +++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -26,6 +26,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/ipc/gfx_param_traits.h" #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" +#include "ui/gfx/range/range.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT @@ -44,6 +45,14 @@ IPC_STRUCT_MEMBER(bool, is_full_page_plugin) IPC_STRUCT_END() +IPC_STRUCT_BEGIN(BrowserPluginHostMsg_SetComposition_Params) + IPC_STRUCT_MEMBER(base::string16, text) + IPC_STRUCT_MEMBER(std::vector<blink::WebCompositionUnderline>, underlines) + IPC_STRUCT_MEMBER(gfx::Range, replacement_range) + IPC_STRUCT_MEMBER(int, selection_start) + IPC_STRUCT_MEMBER(int, selection_end) +IPC_STRUCT_END() + // Browser plugin messages // ----------------------------------------------------------------------------- @@ -65,21 +74,18 @@ // This message is sent from BrowserPlugin to BrowserPluginGuest whenever IME // composition state is updated. -IPC_MESSAGE_CONTROL5( - BrowserPluginHostMsg_ImeSetComposition, - int /* browser_plugin_instance_id */, - std::string /* text */, - std::vector<blink::WebCompositionUnderline> /* underlines */, - int /* selectiont_start */, - int /* selection_end */) +IPC_MESSAGE_CONTROL2(BrowserPluginHostMsg_ImeSetComposition, + int /* browser_plugin_instance_id */, + BrowserPluginHostMsg_SetComposition_Params /* params */) // This message is sent from BrowserPlugin to BrowserPluginGuest to notify that // deleting the current composition and inserting specified text is requested. -IPC_MESSAGE_CONTROL4( +IPC_MESSAGE_CONTROL5( BrowserPluginHostMsg_ImeCommitText, int /* browser_plugin_instance_id */, - std::string /* text */, + base::string16 /* text */, std::vector<blink::WebCompositionUnderline> /* underlines */, + gfx::Range /* replacement_range */, int /* relative_cursor_pos */) // This message is sent from BrowserPlugin to BrowserPluginGuest to notify that
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index 84ea1c0..c8794ab6 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h
@@ -37,7 +37,6 @@ #include "content/common/quota_messages.h" #include "content/common/render_process_messages.h" #include "content/common/resource_messages.h" -#include "content/common/screen_orientation_messages.h" #include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/common/speech_recognition_messages.h"
diff --git a/content/common/frame_owner_properties.cc b/content/common/frame_owner_properties.cc index 8e0f7ead..a29dfc2 100644 --- a/content/common/frame_owner_properties.cc +++ b/content/common/frame_owner_properties.cc
@@ -25,8 +25,6 @@ allow_fullscreen == other.allow_fullscreen && allow_payment_request == other.allow_payment_request && required_csp == other.required_csp && - std::equal(delegated_permissions.begin(), delegated_permissions.end(), - other.delegated_permissions.begin()) && std::equal(allowed_features.begin(), allowed_features.end(), other.allowed_features.begin()); }
diff --git a/content/common/frame_owner_properties.h b/content/common/frame_owner_properties.h index 20d3510..6f48476 100644 --- a/content/common/frame_owner_properties.h +++ b/content/common/frame_owner_properties.h
@@ -9,7 +9,6 @@ #include "content/common/content_export.h" #include "third_party/WebKit/public/platform/WebFeaturePolicy.h" -#include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h" #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h" namespace content { @@ -41,7 +40,6 @@ // https://www.w3.org/TR/csp-embedded-enforcement/#required-csp std::string required_csp; - std::vector<blink::mojom::PermissionName> delegated_permissions; std::vector<blink::WebFeaturePolicyFeature> allowed_features; };
diff --git a/content/common/manifest_manager_messages.h b/content/common/manifest_manager_messages.h index ba06774..8619d99a 100644 --- a/content/common/manifest_manager_messages.h +++ b/content/common/manifest_manager_messages.h
@@ -8,12 +8,16 @@ #include "content/common/content_export.h" #include "content/public/common/manifest.h" #include "ipc/ipc_message_macros.h" +#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT #define IPC_MESSAGE_START ManifestManagerMsgStart +IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebScreenOrientationLockType, + blink::WebScreenOrientationLockDefault, + blink::WebScreenOrientationLockNatural) IPC_ENUM_TRAITS_MAX_VALUE( content::Manifest::Icon::IconPurpose, content::Manifest::Icon::IconPurpose::ICON_PURPOSE_LAST)
diff --git a/content/common/message_port.cc b/content/common/message_port.cc index c89d7b5a..428162e 100644 --- a/content/common/message_port.cc +++ b/content/common/message_port.cc
@@ -4,7 +4,9 @@ #include "content/common/message_port.h" +#include "base/bind.h" #include "base/logging.h" +#include "base/threading/thread_task_runner_handle.h" namespace content { @@ -147,40 +149,86 @@ if (!callback_) return; + DCHECK(!watcher_handle_.is_valid()); + MojoResult rv = CreateWatcher(&State::CallOnHandleReady, &watcher_handle_); + DCHECK_EQ(MOJO_RESULT_OK, rv); + + // We use a scoped_refptr<State> instance as the watch context. This is owned + // by the watch and deleted upon receiving a cancellation notification. + scoped_refptr<State>* state_ref = new scoped_refptr<State>(this); + context_ = reinterpret_cast<uintptr_t>(state_ref); + // NOTE: An HTML MessagePort does not receive an event to tell it when the // peer has gone away, so we only watch for readability here. - MojoResult rv = MojoWatch(handle_.get().value(), - MOJO_HANDLE_SIGNAL_READABLE, - &MessagePort::State::OnHandleReady, - reinterpret_cast<uintptr_t>(this)); - if (rv != MOJO_RESULT_OK) - DVLOG(1) << this << " MojoWatch failed: " << rv; + rv = MojoWatch(watcher_handle_.get().value(), handle_.get().value(), + MOJO_HANDLE_SIGNAL_READABLE, context_); + DCHECK_EQ(MOJO_RESULT_OK, rv); + + ArmWatcher(); } void MessagePort::State::CancelWatch() { - if (!callback_) - return; - - // NOTE: This synchronizes with the thread where OnHandleReady runs so we are - // sure to not be racing with it. - MojoCancelWatch(handle_.get().value(), reinterpret_cast<uintptr_t>(this)); + watcher_handle_.reset(); + context_ = 0; } -// static -void MessagePort::State::OnHandleReady( - uintptr_t context, - MojoResult result, - MojoHandleSignalsState signals_state, - MojoWatchNotificationFlags flags) { - if (result == MOJO_RESULT_OK) { - reinterpret_cast<MessagePort::State*>(context)->callback_.Run(); +MessagePort::State::~State() = default; + +void MessagePort::State::ArmWatcher() { + if (!watcher_handle_.is_valid()) + return; + + uint32_t num_ready_contexts = 1; + uintptr_t ready_context; + MojoResult ready_result; + MojoHandleSignalsState ready_state; + MojoResult rv = + MojoArmWatcher(watcher_handle_.get().value(), &num_ready_contexts, + &ready_context, &ready_result, &ready_state); + if (rv == MOJO_RESULT_OK) + return; + + // The watcher could not be armed because it would notify immediately. + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); + DCHECK_EQ(1u, num_ready_contexts); + DCHECK_EQ(context_, ready_context); + + if (ready_result == MOJO_RESULT_OK) { + // The handle is already signaled, so we trigger a callback now. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&State::OnHandleReady, this, MOJO_RESULT_OK)); + return; + } + + if (ready_result == MOJO_RESULT_FAILED_PRECONDITION) { + DVLOG(1) << this << " MojoArmWatcher failed because of a broken pipe."; + return; + } + + NOTREACHED(); +} + +void MessagePort::State::OnHandleReady(MojoResult result) { + if (result == MOJO_RESULT_OK && callback_) { + callback_.Run(); + ArmWatcher(); } else { // And now his watch is ended. } } -MessagePort::State::~State() { - CancelWatch(); +// static +void MessagePort::State::CallOnHandleReady(uintptr_t context, + MojoResult result, + MojoHandleSignalsState signals_state, + MojoWatcherNotificationFlags flags) { + auto* state_ref = reinterpret_cast<scoped_refptr<State>*>(context); + if (result == MOJO_RESULT_CANCELLED) { + // Last notification. Delete the watch's owned State ref. + delete state_ref; + } else { + (*state_ref)->OnHandleReady(result); + } } } // namespace content
diff --git a/content/common/message_port.h b/content/common/message_port.h index e63d020..fbd7280a 100644 --- a/content/common/message_port.h +++ b/content/common/message_port.h
@@ -13,6 +13,7 @@ #include "base/strings/string16.h" #include "content/common/content_export.h" #include "mojo/public/cpp/system/message_pipe.h" +#include "mojo/public/cpp/system/watcher.h" namespace content { @@ -82,17 +83,25 @@ void AddWatch(); void CancelWatch(); - static void OnHandleReady(uintptr_t context, - MojoResult result, - MojoHandleSignalsState signals_state, - MojoWatchNotificationFlags flags); + mojo::ScopedWatcherHandle watcher_handle_; mojo::ScopedMessagePipeHandle handle_; base::Closure callback_; private: friend class base::RefCountedThreadSafe<State>; + ~State(); + + void ArmWatcher(); + void OnHandleReady(MojoResult result); + + static void CallOnHandleReady(uintptr_t context, + MojoResult result, + MojoHandleSignalsState signals_state, + MojoWatcherNotificationFlags flags); + + uintptr_t context_; }; mutable scoped_refptr<State> state_; };
diff --git a/content/common/screen_orientation_messages.h b/content/common/screen_orientation_messages.h deleted file mode 100644 index c8d1177a..0000000 --- a/content/common/screen_orientation_messages.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// IPC messages for screen orientation. -// Multiply-included message file, hence no include guard. - -#include "content/common/content_export.h" -#include "ipc/ipc_message_macros.h" -#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h" -#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" - -#undef IPC_MESSAGE_EXPORT -#define IPC_MESSAGE_EXPORT CONTENT_EXPORT - -// Only used by content/common/manifest_manager_messages.h. -IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebScreenOrientationLockType, - blink::WebScreenOrientationLockDefault, - blink::WebScreenOrientationLockNatural)
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc index eeb6811d..f92d9cb 100644 --- a/content/gpu/in_process_gpu_thread.cc +++ b/content/gpu/in_process_gpu_thread.cc
@@ -18,6 +18,10 @@ #include "base/android/jni_android.h" #endif +#if defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + namespace content { InProcessGpuThread::InProcessGpuThread( @@ -51,6 +55,12 @@ gpu_process_ = new GpuProcess(io_thread_priority); +#if defined(USE_OZONE) + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForGPU(params); +#endif + gpu::GPUInfo gpu_info; if (!gl::init::InitializeGLOneOff()) VLOG(1) << "gl::init::InitializeGLOneOff failed";
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java index 0cc7719..451abdbb 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
@@ -20,6 +20,7 @@ import org.chromium.base.metrics.RecordHistogram; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; /** * Manages oom bindings used to bound child services. @@ -158,8 +159,8 @@ } } - private final Object mModerateBindingPoolLock = new Object(); - private ModerateBindingPool mModerateBindingPool; + private final AtomicReference<ModerateBindingPool> mModerateBindingPool = + new AtomicReference<>(); /** * Wraps ChildProcessConnection keeping track of additional information needed to manage the @@ -201,10 +202,7 @@ if (connection == null) return; connection.addStrongBinding(); - ModerateBindingPool moderateBindingPool; - synchronized (mModerateBindingPoolLock) { - moderateBindingPool = mModerateBindingPool; - } + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null) moderateBindingPool.removeConnection(this); } @@ -242,10 +240,7 @@ * @param connection The ChildProcessConnection to add to the moderate binding pool. */ private void addConnectionToModerateBindingPool(ChildProcessConnection connection) { - ModerateBindingPool moderateBindingPool; - synchronized (mModerateBindingPoolLock) { - moderateBindingPool = mModerateBindingPool; - } + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null && !connection.isStrongBindingBound()) { moderateBindingPool.addConnection(ManagedConnection.this); } @@ -332,7 +327,7 @@ void clearConnection() { mWasOomProtected = mConnection.isOomProtectedOrWasWhenDied(); - ModerateBindingPool moderateBindingPool = mModerateBindingPool; + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null) moderateBindingPool.removeConnection(this); mConnection = null; } @@ -449,10 +444,7 @@ mBoundForBackgroundPeriod = mLastInForeground; } } - ModerateBindingPool moderateBindingPool; - synchronized (mModerateBindingPoolLock) { - moderateBindingPool = mModerateBindingPool; - } + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null) moderateBindingPool.onSentToBackground(mOnTesting); } @@ -462,10 +454,7 @@ mBoundForBackgroundPeriod.setBoundForBackgroundPeriod(false); mBoundForBackgroundPeriod = null; } - ModerateBindingPool moderateBindingPool; - synchronized (mModerateBindingPoolLock) { - moderateBindingPool = mModerateBindingPool; - } + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null) moderateBindingPool.onBroughtToForeground(); } @@ -501,23 +490,19 @@ @Override public void startModerateBindingManagement( Context context, int maxSize, boolean moderateBindingTillBackgrounded) { - synchronized (mModerateBindingPoolLock) { - if (mIsLowMemoryDevice || mModerateBindingPool != null) return; - + if (mIsLowMemoryDevice) return; + ModerateBindingPool pool = new ModerateBindingPool(maxSize); + if (mModerateBindingPool.compareAndSet(null, pool)) { mModerateBindingTillBackgrounded = moderateBindingTillBackgrounded; Log.i(TAG, "Moderate binding enabled: maxSize=%d", maxSize); - mModerateBindingPool = new ModerateBindingPool(maxSize); - if (context != null) context.registerComponentCallbacks(mModerateBindingPool); + if (context != null) context.registerComponentCallbacks(pool); } } @Override public void releaseAllModerateBindings() { - ModerateBindingPool moderateBindingPool; - synchronized (mModerateBindingPoolLock) { - moderateBindingPool = mModerateBindingPool; - } + ModerateBindingPool moderateBindingPool = mModerateBindingPool.get(); if (moderateBindingPool != null) { Log.i(TAG, "Release all moderate bindings: %d", moderateBindingPool.size()); moderateBindingPool.evictAll();
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java index 7807b619..ea6f619 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java
@@ -65,6 +65,7 @@ /** * @return The {@link Handler} used for this InputConnection. */ + @Override @VisibleForTesting Handler getHandler();
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java index c5413d3..2ecd31d 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
@@ -409,6 +409,7 @@ /** * @see InputConnection#deleteSurroundingTextInCodePoints(int, int) */ + @Override public boolean deleteSurroundingTextInCodePoints( final int beforeLength, final int afterLength) { if (DEBUG_LOGS) { @@ -647,6 +648,7 @@ * @see InputConnection#closeConnection() */ // TODO(crbug.com/635567): Fix this properly. + @Override @SuppressLint("MissingSuperCall") public void closeConnection() { if (DEBUG_LOGS) Log.w(TAG, "closeConnection");
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 3050b79..0f8738e 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -311,6 +311,7 @@ mNativeWebContentsAndroid, enableHiding, enableShowing, animate); } + @Override public void scrollFocusedEditableNodeIntoView() { // The native side keeps track of whether the zoom and scroll actually occurred. It is // more efficient to do it this way and sometimes fire an unnecessary message rather
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index a6ef29c..6cda4685 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -57,7 +57,7 @@ // Enables faster location.reload() to use a reload mode that revalidates only // main resource forcibly. https://crbug.com/670237. const base::Feature kFasterLocationReload{"FasterLocationReload", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Enables the Feature Policy framework for granting and removing access to // other features through HTTP headers.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 99a7745e1..3497d167 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -584,6 +584,8 @@ "media/media_stream_constraints_util.h", "media/media_stream_constraints_util_sets.cc", "media/media_stream_constraints_util_sets.h", + "media/media_stream_constraints_util_video_content.cc", + "media/media_stream_constraints_util_video_content.h", "media/media_stream_constraints_util_video_device.cc", "media/media_stream_constraints_util_video_device.h", "media/media_stream_dispatcher.cc",
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index 035f3779..b3c3250f 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -548,22 +548,28 @@ bool BrowserPlugin::setComposition( const blink::WebString& text, const blink::WebVector<blink::WebCompositionUnderline>& underlines, + const blink::WebRange& replacementRange, int selectionStart, int selectionEnd) { if (!attached()) return false; - std::vector<blink::WebCompositionUnderline> std_underlines; + BrowserPluginHostMsg_SetComposition_Params params; + params.text = text.utf16(); for (size_t i = 0; i < underlines.size(); ++i) { - std_underlines.push_back(underlines[i]); + params.underlines.push_back(underlines[i]); } + params.replacement_range = + replacementRange.isNull() + ? gfx::Range::InvalidRange() + : gfx::Range(static_cast<uint32_t>(replacementRange.startOffset()), + static_cast<uint32_t>(replacementRange.endOffset())); + params.selection_start = selectionStart; + params.selection_end = selectionEnd; + BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ImeSetComposition( - browser_plugin_instance_id_, - text.utf8(), - std_underlines, - selectionStart, - selectionEnd)); + browser_plugin_instance_id_, params)); // TODO(kochi): This assumes the IPC handling always succeeds. return true; } @@ -571,6 +577,7 @@ bool BrowserPlugin::commitText( const blink::WebString& text, const blink::WebVector<blink::WebCompositionUnderline>& underlines, + const blink::WebRange& replacementRange, int relative_cursor_pos) { if (!attached()) return false; @@ -579,10 +586,15 @@ for (size_t i = 0; i < underlines.size(); ++i) { std_underlines.push_back(std_underlines[i]); } + gfx::Range replacement_range = + replacementRange.isNull() + ? gfx::Range::InvalidRange() + : gfx::Range(static_cast<uint32_t>(replacementRange.startOffset()), + static_cast<uint32_t>(replacementRange.endOffset())); BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ImeCommitText( - browser_plugin_instance_id_, text.utf8(), std_underlines, - relative_cursor_pos)); + browser_plugin_instance_id_, text.utf16(), std_underlines, + replacement_range, relative_cursor_pos)); // TODO(kochi): This assumes the IPC handling always succeeds. return true; }
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index 47900ad..9893064 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -113,11 +113,13 @@ bool setComposition( const blink::WebString& text, const blink::WebVector<blink::WebCompositionUnderline>& underlines, + const blink::WebRange& replacementRange, int selectionStart, int selectionEnd) override; bool commitText( const blink::WebString& text, const blink::WebVector<blink::WebCompositionUnderline>& underlines, + const blink::WebRange& replacementRange, int relative_cursor_pos) override; bool finishComposingText( blink::WebInputMethodController::ConfirmCompositionBehavior
diff --git a/content/renderer/frame_owner_properties.cc b/content/renderer/frame_owner_properties.cc index bd0b4ce..9941cec 100644 --- a/content/renderer/frame_owner_properties.cc +++ b/content/renderer/frame_owner_properties.cc
@@ -23,9 +23,6 @@ result.allow_fullscreen = web_frame_owner_properties.allowFullscreen; result.allow_payment_request = web_frame_owner_properties.allowPaymentRequest; result.required_csp = web_frame_owner_properties.requiredCsp.utf8(); - std::copy(web_frame_owner_properties.delegatedPermissions.begin(), - web_frame_owner_properties.delegatedPermissions.end(), - std::back_inserter(result.delegated_permissions)); std::copy(web_frame_owner_properties.allowedFeatures.begin(), web_frame_owner_properties.allowedFeatures.end(), std::back_inserter(result.allowed_features)); @@ -46,8 +43,6 @@ result.allowPaymentRequest = frame_owner_properties.allow_payment_request; result.requiredCsp = blink::WebString::fromUTF8(frame_owner_properties.required_csp); - result.delegatedPermissions = blink::WebVector<blink::mojom::PermissionName>( - frame_owner_properties.delegated_permissions); result.allowedFeatures = blink::WebVector<blink::WebFeaturePolicyFeature>( frame_owner_properties.allowed_features);
diff --git a/content/renderer/media/media_stream_constraints_util_video_content.cc b/content/renderer/media/media_stream_constraints_util_video_content.cc new file mode 100644 index 0000000..e13c2439 --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_content.cc
@@ -0,0 +1,331 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/media_stream_constraints_util_video_content.h" + +#include <cmath> +#include <utility> +#include <vector> + +#include "content/renderer/media/media_stream_constraints_util_sets.h" +#include "content/renderer/media/media_stream_video_source.h" +#include "media/base/limits.h" +#include "third_party/WebKit/public/platform/WebMediaConstraints.h" +#include "third_party/WebKit/public/platform/WebString.h" + +namespace content { + +namespace { + +using Point = ResolutionSet::Point; +using StringSet = DiscreteSet<std::string>; +using BoolSet = DiscreteSet<bool>; + +// Hard upper and lower bound frame rates for tab/desktop capture. +constexpr double kMaxScreenCastFrameRate = 120.0; +constexpr double kMinScreenCastFrameRate = 1.0 / 60.0; + +constexpr double kDefaultFrameRate = MediaStreamVideoSource::kDefaultFrameRate; + +constexpr int kMinScreenCastDimension = 1; +constexpr int kMaxScreenCastDimension = media::limits::kMaxDimension - 1; +constexpr double kMinScreenCastAspectRatio = + static_cast<double>(kMinScreenCastDimension) / + static_cast<double>(kMaxScreenCastDimension); +constexpr double kMaxScreenCastAspectRatio = + static_cast<double>(kMaxScreenCastDimension) / + static_cast<double>(kMinScreenCastDimension); + +StringSet StringSetFromConstraint(const blink::StringConstraint& constraint) { + if (!constraint.hasExact()) + return StringSet::UniversalSet(); + + std::vector<std::string> elements; + for (const auto& entry : constraint.exact()) + elements.push_back(entry.ascii()); + + return StringSet(std::move(elements)); +} + +BoolSet BoolSetFromConstraint(const blink::BooleanConstraint& constraint) { + if (!constraint.hasExact()) + return BoolSet::UniversalSet(); + + return BoolSet({constraint.exact()}); +} + +using DoubleRangeSet = NumericRangeSet<double>; + +class VideoContentCaptureCandidates { + public: + VideoContentCaptureCandidates() + : device_id_set(StringSet::UniversalSet()), + noise_reduction_set(BoolSet::UniversalSet()) {} + explicit VideoContentCaptureCandidates( + const blink::WebMediaTrackConstraintSet& constraint_set) + : resolution_set(ResolutionSet::FromConstraintSet(constraint_set)), + frame_rate_set( + DoubleRangeSet::FromConstraint(constraint_set.frameRate)), + device_id_set(StringSetFromConstraint(constraint_set.deviceId)), + noise_reduction_set( + BoolSetFromConstraint(constraint_set.googNoiseReduction)) {} + + VideoContentCaptureCandidates(VideoContentCaptureCandidates&& other) = + default; + VideoContentCaptureCandidates& operator=( + VideoContentCaptureCandidates&& other) = default; + + bool IsEmpty() const { + return resolution_set.IsEmpty() || frame_rate_set.IsEmpty() || + device_id_set.IsEmpty() || noise_reduction_set.IsEmpty(); + } + + VideoContentCaptureCandidates Intersection( + const VideoContentCaptureCandidates& other) { + VideoContentCaptureCandidates intersection; + intersection.resolution_set = + resolution_set.Intersection(other.resolution_set); + intersection.frame_rate_set = + frame_rate_set.Intersection(other.frame_rate_set); + intersection.device_id_set = + device_id_set.Intersection(other.device_id_set); + intersection.noise_reduction_set = + noise_reduction_set.Intersection(other.noise_reduction_set); + return intersection; + } + + ResolutionSet resolution_set; + DoubleRangeSet frame_rate_set; + StringSet device_id_set; + BoolSet noise_reduction_set; +}; + +ResolutionSet ScreenCastResolutionCapabilities() { + return ResolutionSet(kMinScreenCastDimension, kMaxScreenCastDimension, + kMinScreenCastDimension, kMaxScreenCastDimension, + kMinScreenCastAspectRatio, kMaxScreenCastAspectRatio); +} + +// TODO(guidou): Update this policy to better match the way +// WebContentsCaptureMachine::ComputeOptimalViewSize() interprets +// resolution-change policies. See http://crbug.com/701302. +media::ResolutionChangePolicy SelectResolutionPolicyFromCandidates( + const ResolutionSet& resolution_set) { + ResolutionSet capabilities = ScreenCastResolutionCapabilities(); + bool can_adjust_resolution = + resolution_set.min_height() <= capabilities.min_height() && + resolution_set.max_height() >= capabilities.max_height() && + resolution_set.min_width() <= capabilities.min_width() && + resolution_set.max_width() >= capabilities.max_width() && + resolution_set.min_aspect_ratio() <= capabilities.min_aspect_ratio() && + resolution_set.max_aspect_ratio() >= capabilities.max_aspect_ratio(); + + return can_adjust_resolution ? media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT + : media::RESOLUTION_POLICY_FIXED_RESOLUTION; +} + +int RoundToInt(double d) { + return static_cast<int>(std::round(d)); +} + +gfx::Size ToGfxSize(const Point& point) { + return gfx::Size(RoundToInt(point.width()), RoundToInt(point.height())); +} + +double SelectFrameRateFromCandidates( + const DoubleRangeSet& candidate_set, + const blink::WebMediaTrackConstraintSet& basic_constraint_set) { + double frame_rate = basic_constraint_set.frameRate.hasIdeal() + ? basic_constraint_set.frameRate.ideal() + : kDefaultFrameRate; + if (frame_rate > candidate_set.Max()) + frame_rate = candidate_set.Max(); + else if (frame_rate < candidate_set.Min()) + frame_rate = candidate_set.Min(); + + return frame_rate; +} + +media::VideoCaptureParams SelectVideoCaptureParamsFromCandidates( + const VideoContentCaptureCandidates& candidates, + const blink::WebMediaTrackConstraintSet& basic_constraint_set) { + double requested_frame_rate = SelectFrameRateFromCandidates( + candidates.frame_rate_set, basic_constraint_set); + Point requested_resolution = + candidates.resolution_set.SelectClosestPointToIdeal(basic_constraint_set); + media::VideoCaptureParams params; + params.requested_format = media::VideoCaptureFormat( + ToGfxSize(requested_resolution), static_cast<float>(requested_frame_rate), + media::PIXEL_FORMAT_I420); + params.resolution_change_policy = + SelectResolutionPolicyFromCandidates(candidates.resolution_set); + // Content capture always uses default power-line frequency. + DCHECK(params.IsValid()); + + return params; +} + +std::string SelectDeviceIDFromCandidates( + const StringSet& candidates, + const blink::WebMediaTrackConstraintSet& basic_constraint_set) { + DCHECK(!candidates.IsEmpty()); + if (basic_constraint_set.deviceId.hasIdeal()) { + // If there are multiple elements specified by ideal, break ties by choosing + // the first one that satisfies the constraints. + for (const auto& ideal_entry : basic_constraint_set.deviceId.ideal()) { + std::string ideal_value = ideal_entry.ascii(); + if (candidates.Contains(ideal_value)) { + return ideal_value; + } + } + } + + // Return the empty string if nothing is specified in the constraints. + // The empty string is treated as a default device ID by the browser. + if (candidates.is_universal()) { + return std::string(); + } + + // If there are multiple elements that satisfy the constraints, break ties by + // using the element that was specified first. + return candidates.FirstElement(); +} + +rtc::Optional<bool> SelectNoiseReductionFromCandidates( + const BoolSet& candidates, + const blink::WebMediaTrackConstraintSet& basic_constraint_set) { + DCHECK(!candidates.IsEmpty()); + if (basic_constraint_set.googNoiseReduction.hasIdeal() && + candidates.Contains(basic_constraint_set.googNoiseReduction.ideal())) { + return rtc::Optional<bool>(basic_constraint_set.googNoiseReduction.ideal()); + } + + if (candidates.is_universal()) + return rtc::Optional<bool>(); + + // A non-universal BoolSet can have at most one element. + return rtc::Optional<bool>(candidates.FirstElement()); +} + +VideoContentCaptureSourceSelectionResult SelectResultFromCandidates( + const VideoContentCaptureCandidates& candidates, + const blink::WebMediaTrackConstraintSet& basic_constraint_set) { + std::string device_id = SelectDeviceIDFromCandidates(candidates.device_id_set, + basic_constraint_set); + media::VideoCaptureParams capture_params = + SelectVideoCaptureParamsFromCandidates(candidates, basic_constraint_set); + + rtc::Optional<bool> noise_reduction = SelectNoiseReductionFromCandidates( + candidates.noise_reduction_set, basic_constraint_set); + + return VideoContentCaptureSourceSelectionResult( + std::move(device_id), noise_reduction, capture_params); +} + +VideoContentCaptureSourceSelectionResult UnsatisfiedConstraintsResult( + const VideoContentCaptureCandidates& candidates, + const blink::WebMediaTrackConstraintSet& constraint_set) { + DCHECK(candidates.IsEmpty()); + if (candidates.resolution_set.IsHeightEmpty()) { + return VideoContentCaptureSourceSelectionResult( + constraint_set.height.name()); + } else if (candidates.resolution_set.IsWidthEmpty()) { + return VideoContentCaptureSourceSelectionResult( + constraint_set.width.name()); + } else if (candidates.resolution_set.IsAspectRatioEmpty()) { + return VideoContentCaptureSourceSelectionResult( + constraint_set.aspectRatio.name()); + } else if (candidates.frame_rate_set.IsEmpty()) { + return VideoContentCaptureSourceSelectionResult( + constraint_set.frameRate.name()); + } else if (candidates.noise_reduction_set.IsEmpty()) { + return VideoContentCaptureSourceSelectionResult( + constraint_set.googNoiseReduction.name()); + } else { + DCHECK(candidates.device_id_set.IsEmpty()); + return VideoContentCaptureSourceSelectionResult( + constraint_set.deviceId.name()); + } +} + +} // namespace + +VideoContentCaptureSourceSelectionResult:: + VideoContentCaptureSourceSelectionResult(const char* failed_constraint_name) + : failed_constraint_name_(failed_constraint_name) {} + +VideoContentCaptureSourceSelectionResult:: + VideoContentCaptureSourceSelectionResult( + std::string device_id, + const rtc::Optional<bool>& noise_reduction, + media::VideoCaptureParams capture_params) + : failed_constraint_name_(nullptr), + device_id_(std::move(device_id)), + noise_reduction_(noise_reduction), + capture_params_(capture_params) {} + +VideoContentCaptureSourceSelectionResult:: + VideoContentCaptureSourceSelectionResult( + const VideoContentCaptureSourceSelectionResult& other) = default; +VideoContentCaptureSourceSelectionResult:: + VideoContentCaptureSourceSelectionResult( + VideoContentCaptureSourceSelectionResult&& other) = default; +VideoContentCaptureSourceSelectionResult:: + ~VideoContentCaptureSourceSelectionResult() = default; +VideoContentCaptureSourceSelectionResult& +VideoContentCaptureSourceSelectionResult::operator=( + const VideoContentCaptureSourceSelectionResult& other) = default; +VideoContentCaptureSourceSelectionResult& +VideoContentCaptureSourceSelectionResult::operator=( + VideoContentCaptureSourceSelectionResult&& other) = default; + +int VideoContentCaptureSourceSelectionResult::Height() const { + DCHECK(HasValue()); + return capture_params_.requested_format.frame_size.height(); +} + +int VideoContentCaptureSourceSelectionResult::Width() const { + DCHECK(HasValue()); + return capture_params_.requested_format.frame_size.width(); +} + +float VideoContentCaptureSourceSelectionResult::FrameRate() const { + DCHECK(HasValue()); + return capture_params_.requested_format.frame_rate; +} + +media::ResolutionChangePolicy +VideoContentCaptureSourceSelectionResult::ResolutionChangePolicy() const { + DCHECK(HasValue()); + return capture_params_.resolution_change_policy; +} + +VideoContentCaptureSourceSelectionResult +SelectVideoContentCaptureSourceSettings( + const blink::WebMediaConstraints& constraints) { + VideoContentCaptureCandidates candidates; + candidates.resolution_set = ScreenCastResolutionCapabilities(); + candidates.frame_rate_set = + DoubleRangeSet(kMinScreenCastFrameRate, kMaxScreenCastFrameRate); + // candidates.device_id_set and candidates.noise_reduction_set are + // automatically initialized with the universal set. + + candidates = candidates.Intersection( + VideoContentCaptureCandidates(constraints.basic())); + if (candidates.IsEmpty()) + return UnsatisfiedConstraintsResult(candidates, constraints.basic()); + + for (const auto& advanced_set : constraints.advanced()) { + VideoContentCaptureCandidates advanced_candidates(advanced_set); + VideoContentCaptureCandidates intersection = + candidates.Intersection(advanced_candidates); + if (!intersection.IsEmpty()) + candidates = std::move(intersection); + } + + DCHECK(!candidates.IsEmpty()); + return SelectResultFromCandidates(candidates, constraints.basic()); +} + +} // namespace content
diff --git a/content/renderer/media/media_stream_constraints_util_video_content.h b/content/renderer/media/media_stream_constraints_util_video_content.h new file mode 100644 index 0000000..250b4ecd --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_content.h
@@ -0,0 +1,84 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_CONTENT_H_ +#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_CONTENT_H_ + +#include <string> + +#include "base/logging.h" +#include "content/common/content_export.h" +#include "media/capture/video_capture_types.h" +#include "third_party/webrtc/base/optional.h" + +namespace blink { +class WebMediaConstraints; +} + +namespace content { + +class CONTENT_EXPORT VideoContentCaptureSourceSelectionResult { + public: + // Creates a result without value and with the given |failed_constraint_name|. + // Does not take ownership of |failed_constraint_name|, so it must be null or + // point to a string that remains accessible. + explicit VideoContentCaptureSourceSelectionResult( + const char* failed_constraint_name); + + // Creates a result with the given values. |device_id| is moved to an internal + // field. + VideoContentCaptureSourceSelectionResult( + std::string device_id, + const rtc::Optional<bool>& noise_reduction, + media::VideoCaptureParams capture_params); + + VideoContentCaptureSourceSelectionResult( + const VideoContentCaptureSourceSelectionResult& other); + VideoContentCaptureSourceSelectionResult& operator=( + const VideoContentCaptureSourceSelectionResult& other); + VideoContentCaptureSourceSelectionResult( + VideoContentCaptureSourceSelectionResult&& other); + VideoContentCaptureSourceSelectionResult& operator=( + VideoContentCaptureSourceSelectionResult&& other); + ~VideoContentCaptureSourceSelectionResult(); + + bool HasValue() const { return failed_constraint_name_ == nullptr; } + + // Accessors. + const char* failed_constraint_name() const { return failed_constraint_name_; } + const std::string& device_id() const { + DCHECK(HasValue()); + return device_id_; + } + const rtc::Optional<bool>& noise_reduction() const { + DCHECK(HasValue()); + return noise_reduction_; + } + media::VideoCaptureParams capture_params() const { + DCHECK(HasValue()); + return capture_params_; + } + + // Convenience accessors for fields embedded in the |capture_params_| field. + int Height() const; + int Width() const; + float FrameRate() const; + media::ResolutionChangePolicy ResolutionChangePolicy() const; + + private: + const char* failed_constraint_name_; + std::string device_id_; + rtc::Optional<bool> noise_reduction_; + media::VideoCaptureParams capture_params_; +}; + +// This function performs source and source-settings selection for content +// video capture based on the given |constraints|. +VideoContentCaptureSourceSelectionResult CONTENT_EXPORT +SelectVideoContentCaptureSourceSettings( + const blink::WebMediaConstraints& constraints); + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_CONTENT_H_
diff --git a/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc new file mode 100644 index 0000000..212391e --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_content_unittest.cc
@@ -0,0 +1,1661 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/media_stream_constraints_util_video_content.h" + +#include <cmath> +#include <string> + +#include "content/renderer/media/media_stream_video_source.h" +#include "content/renderer/media/mock_constraint_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebMediaConstraints.h" + +namespace content { + +namespace { + +void CheckNonResolutionDefaults( + const VideoContentCaptureSourceSelectionResult& result) { + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); +} + +void CheckNonFrameRateDefaults( + const VideoContentCaptureSourceSelectionResult& result) { + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); +} + +} // namespace + +class MediaStreamConstraintsUtilVideoContentTest : public testing::Test { + protected: + VideoContentCaptureSourceSelectionResult SelectSettings() { + blink::WebMediaConstraints constraints = + constraint_factory_.CreateWebMediaConstraints(); + return SelectVideoContentCaptureSourceSettings(constraints); + } + + MockConstraintFactory constraint_factory_; +}; + +// The Unconstrained test checks the default selection criteria. +TEST_F(MediaStreamConstraintsUtilVideoContentTest, Unconstrained) { + constraint_factory_.Reset(); + auto result = SelectSettings(); + + // All settings should have default values. + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); +} + +// The "Overconstrained" tests verify that failure of any single required +// constraint results in failure to select a candidate. +TEST_F(MediaStreamConstraintsUtilVideoContentTest, OverconstrainedOnHeight) { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMax(0); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, OverconstrainedOnWidth) { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMax(0); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + OverconstrainedOnAspectRatio) { + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setMax(0.00001); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, OverconstrainedOnFrameRate) { + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setExact(123467890.0); + auto result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setMin(123467890.0); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name()); + + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setMax(0.0); + result = SelectSettings(); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name()); +} + +// The "Mandatory" and "Ideal" tests check that various selection criteria work +// for each individual constraint in the basic constraint set. +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryDeviceID) { + const std::string kDeviceID = "Some ID"; + constraint_factory_.Reset(); + constraint_factory_.basic().deviceId.setExact( + blink::WebString::fromASCII(kDeviceID)); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kDeviceID, result.device_id()); + // Other settings should have default values. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealDeviceID) { + const std::string kDeviceID = "Some ID"; + const std::string kIdealID = "Ideal ID"; + blink::WebVector<blink::WebString> device_ids(static_cast<size_t>(2)); + device_ids[0] = blink::WebString::fromASCII(kDeviceID); + device_ids[1] = blink::WebString::fromASCII(kIdealID); + constraint_factory_.Reset(); + constraint_factory_.basic().deviceId.setExact(device_ids); + + blink::WebVector<blink::WebString> ideal_id(static_cast<size_t>(1)); + ideal_id[0] = blink::WebString::fromASCII(kIdealID); + constraint_factory_.basic().deviceId.setIdeal(ideal_id); + + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealID, result.device_id()); + // Other settings should have default values. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryNoiseReduction) { + constraint_factory_.Reset(); + const bool kNoiseReductionValues[] = {true, false}; + for (auto noise_reduction : kNoiseReductionValues) { + constraint_factory_.basic().googNoiseReduction.setExact(noise_reduction); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(noise_reduction, result.noise_reduction()); + // Other settings should have default values. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + EXPECT_EQ(std::string(), result.device_id()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealNoiseReduction) { + constraint_factory_.Reset(); + const bool kNoiseReductionValues[] = {true, false}; + for (auto noise_reduction : kNoiseReductionValues) { + constraint_factory_.basic().googNoiseReduction.setIdeal(noise_reduction); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(noise_reduction, result.noise_reduction()); + // Other settings should have default values. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + EXPECT_EQ(std::string(), result.device_id()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryExactHeight) { + constraint_factory_.Reset(); + const int kHeight = 1000; + constraint_factory_.basic().height.setExact(kHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kHeight, result.Height()); + // The algorithm tries to preserve the default aspect ratio. + EXPECT_EQ(std::round(kHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMinHeight) { + constraint_factory_.Reset(); + const int kHeight = 1000; + constraint_factory_.basic().height.setMin(kHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kHeight is greater that the default, so expect kHeight. + EXPECT_EQ(kHeight, result.Height()); + EXPECT_EQ(std::round(kHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + + const int kSmallHeight = 100; + constraint_factory_.basic().height.setMin(kSmallHeight); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallHeight is less that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxHeight) { + constraint_factory_.Reset(); + const int kHeight = 1000; + constraint_factory_.basic().height.setMax(kHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kHeight is greater that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + + const int kSmallHeight = 100; + constraint_factory_.basic().height.setMax(kSmallHeight); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallHeight is less that the default, so expect kSmallHeight. + EXPECT_EQ(kSmallHeight, result.Height()); + EXPECT_EQ( + std::round(kSmallHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryHeightRange) { + constraint_factory_.Reset(); + { + const int kMinHeight = 300; + const int kMaxHeight = 1000; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The range includes the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + } + + { + const int kMinHeight = 900; + const int kMaxHeight = 1000; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is greater than the default, so expect the range minimum. + EXPECT_EQ(kMinHeight, result.Height()); + EXPECT_EQ( + std::round(kMinHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + { + const int kMinHeight = 300; + const int kMaxHeight = 400; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is less than the default, so expect the range maximum. + EXPECT_EQ(kMaxHeight, result.Height()); + EXPECT_EQ( + std::round(kMaxHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealHeight) { + // Unconstrained. + { + constraint_factory_.Reset(); + const int kIdealHeight = 1000; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealHeight, result.Height()); + // When ideal height is given, the algorithm returns a width that is closest + // to height * kDefaultAspectRatio. + EXPECT_EQ( + std::round(kIdealHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal greater than maximum. + { + constraint_factory_.Reset(); + const int kIdealHeight = 1000; + const int kMaxHeight = 800; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal height is greater than the maximum, expect maximum. + EXPECT_EQ(kMaxHeight, result.Height()); + // Expect closest to kMaxHeight * kDefaultAspectRatio. + EXPECT_EQ( + std::round(kMaxHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal less than minimum. + { + constraint_factory_.Reset(); + const int kIdealHeight = 1000; + const int kMinHeight = 1200; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + constraint_factory_.basic().height.setMin(kMinHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal height is less than the minimum, expect minimum. + EXPECT_EQ(kMinHeight, result.Height()); + // Expect closest to kMinHeight * kDefaultAspectRatio. + EXPECT_EQ( + std::round(kMinHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal intersects a box. + { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(500); + constraint_factory_.basic().height.setMax(1000); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + const int kIdealHeight = 750; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal height is included in the bounding box. + EXPECT_EQ(kIdealHeight, result.Height()); + // Expect width closest to kIdealHeight * kDefaultAspectRatio, which is + // outside the box. Closest is max width. + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().width.setMin(1200); + constraint_factory_.basic().width.setMax(2000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealHeight, result.Height()); + // kIdealHeight * kDefaultAspectRatio is outside the box. Closest is + // min width. + EXPECT_EQ(constraint_factory_.basic().width.min(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealHeight, result.Height()); + // kIdealHeight * kDefaultAspectRatio is outside the box. Closest is + // max width. + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the box, closest to the side coinciding with max height. + { + const int kMaxHeight = 1000; + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(500); + constraint_factory_.basic().height.setMax(kMaxHeight); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + constraint_factory_.basic().height.setIdeal(1200); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxHeight, result.Height()); + // Expect width closest to kMaxHeight * kDefaultAspectRatio, which is + // outside the box. Closest it max width. + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().width.setMin(1500); + constraint_factory_.basic().width.setMax(2000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxHeight, result.Height()); + // kMaxHeight * kDefaultAspectRatio is outside the box. Closest is min + // width. + EXPECT_EQ(constraint_factory_.basic().width.min(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().width.setMin(100); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxHeight, result.Height()); + // kMaxHeight * kDefaultAspectRatio is within the width limits. + EXPECT_EQ( + std::round(kMaxHeight * MediaStreamVideoSource::kDefaultAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the constrained set, closest to a single point. + { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(500); + constraint_factory_.basic().height.setMax(1000); + constraint_factory_.basic().width.setMin(500); + constraint_factory_.basic().width.setMax(1000); + constraint_factory_.basic().aspectRatio.setMin(1.0); + constraint_factory_.basic().height.setIdeal(1200); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // (max-height, max-width) is the single point closest to the ideal line. + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryExactWidth) { + constraint_factory_.Reset(); + const int kWidth = 1000; + constraint_factory_.basic().width.setExact(kWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kWidth, result.Width()); + EXPECT_EQ(std::round(kWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMinWidth) { + constraint_factory_.Reset(); + const int kWidth = 1000; + constraint_factory_.basic().width.setMin(kWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kWidth is greater that the default, so expect kWidth. + EXPECT_EQ(kWidth, result.Width()); + EXPECT_EQ(std::round(kWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + + const int kSmallWidth = 100; + constraint_factory_.basic().width.setMin(kSmallWidth); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallWidth is less that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxWidth) { + constraint_factory_.Reset(); + const int kWidth = 1000; + constraint_factory_.basic().width.setMax(kWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kWidth is greater that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + CheckNonResolutionDefaults(result); + + const int kSmallWidth = 100; + constraint_factory_.basic().width.setMax(kSmallWidth); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallWidth is less that the default, so expect kSmallWidth. + EXPECT_EQ(kSmallWidth, result.Width()); + EXPECT_EQ( + std::round(kSmallWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryWidthRange) { + constraint_factory_.Reset(); + { + const int kMinWidth = 300; + const int kMaxWidth = 1000; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The range includes the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + CheckNonResolutionDefaults(result); + } + + { + const int kMinWidth = 900; + const int kMaxWidth = 1000; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is greater than the default, so expect the range minimum. + EXPECT_EQ(kMinWidth, result.Width()); + EXPECT_EQ( + std::round(kMinWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } + + { + const int kMinWidth = 300; + const int kMaxWidth = 400; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is less than the default, so expect the range maximum. + EXPECT_EQ(kMaxWidth, result.Width()); + EXPECT_EQ( + std::round(kMaxWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealWidth) { + // Unconstrained + { + constraint_factory_.Reset(); + const int kIdealWidth = 1000; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealWidth, result.Width()); + // When ideal width is given, the algorithm returns a height that is closest + // to width / kDefaultAspectRatio. + EXPECT_EQ( + std::round(kIdealWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } + + // Ideal greater than maximum. + { + constraint_factory_.Reset(); + const int kIdealWidth = 1000; + const int kMaxWidth = 800; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxWidth, result.Width()); + // Expect closest to kMaxWidth / kDefaultAspectRatio. + EXPECT_EQ( + std::round(kMaxWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } + + // Ideal less than minimum. + { + constraint_factory_.Reset(); + const int kIdealWidth = 1000; + const int kMinWidth = 1200; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + constraint_factory_.basic().width.setMin(kMinWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMinWidth, result.Width()); + // Expect closest to kMinWidth / kDefaultAspectRatio. + EXPECT_EQ( + std::round(kMinWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } + + // Ideal intersects a box. + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMin(500); + constraint_factory_.basic().width.setMax(1000); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + const int kIdealWidth = 750; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal width is included in the bounding box. + EXPECT_EQ(kIdealWidth, result.Width()); + // Expect height closest to kIdealWidth / kDefaultAspectRatio, which is + // outside the box. Closest is max height. + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(1200); + constraint_factory_.basic().height.setMax(2000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealWidth, result.Width()); + // kIdealWidth / kDefaultAspectRatio outside the box. Closest is + // min height. + EXPECT_EQ(constraint_factory_.basic().height.min(), result.Height()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealWidth, result.Width()); + // kIdealWidth / kDefaultAspectRatio is outside the box. Closest is max + // height. + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the box, closest to the side coinciding with max width. + { + const int kMaxWidth = 1000; + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMin(500); + constraint_factory_.basic().width.setMax(kMaxWidth); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + constraint_factory_.basic().width.setIdeal(1200); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxWidth, result.Width()); + // kMaxWidth / kDefaultAspectRatio is outside the box. Closest is max + // height. + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(1500); + constraint_factory_.basic().height.setMax(2000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxWidth, result.Width()); + // kMaxWidth / kDefaultAspectRatio is outside the box. Closest is + // min height. + EXPECT_EQ(constraint_factory_.basic().height.min(), result.Height()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(100); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxWidth, result.Width()); + // kMaxWidth / kDefaultAspectRatio is within the height limits. + EXPECT_EQ( + std::round(kMaxWidth / MediaStreamVideoSource::kDefaultAspectRatio), + result.Height()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the constrained set, closest to a single point. + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + constraint_factory_.basic().aspectRatio.setMax(1.0); + constraint_factory_.basic().width.setIdeal(1200); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // (max-width, max-height) is the single point closest to the ideal line. + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryExactAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Given that the default aspect ratio cannot be preserved, the algorithm + // tries to preserve, among the default height or width, the one that leads + // to highest area. In this case, height is preserved. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(std::round(MediaStreamVideoSource::kDefaultHeight * kAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMinAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setMin(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kAspectRatio is greater that the default, so expect kAspectRatio. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(std::round(MediaStreamVideoSource::kDefaultHeight * kAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + + const double kSmallAspectRatio = 0.5; + constraint_factory_.basic().aspectRatio.setMin(kSmallAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallAspectRatio is less that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setMax(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kAspectRatio is greater that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + + const double kSmallAspectRatio = 0.5; + constraint_factory_.basic().aspectRatio.setMax(kSmallAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kSmallAspectRatio is less that the default, so expect kSmallAspectRatio. + // Prefer to preserve default width since that leads to larger area than + // preserving default height. + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultWidth / kSmallAspectRatio), + result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryRangeAspectRatio) { + constraint_factory_.Reset(); + { + const double kMinAspectRatio = 0.5; + const double kMaxAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Range includes default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + } + + { + const double kMinAspectRatio = 2.0; + const double kMaxAspectRatio = 3.0; + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is greater than the default. Expect the minimum. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultHeight * kMinAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + { + const double kMinAspectRatio = 0.5; + const double kMaxAspectRatio = 1.0; + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is less than the default. Expect the maximum. + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultWidth / kMaxAspectRatio), + result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealAspectRatio) { + // Unconstrained. + { + constraint_factory_.Reset(); + const double kIdealAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultHeight * kIdealAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal greater than maximum. + { + constraint_factory_.Reset(); + const double kIdealAspectRatio = 2.0; + const double kMaxAspectRatio = 1.5; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal height is greater than the maximum, expect maximum. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultHeight * kMaxAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal less than minimum. + { + constraint_factory_.Reset(); + const double kIdealAspectRatio = 1.0; + const double kMinAspectRatio = 1.5; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal height is greater than the maximum, expect maximum. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ( + std::round(MediaStreamVideoSource::kDefaultHeight * kMinAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal intersects a box. + { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + const int kIdealAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal aspect-ratio is included in the bounding box, with the value + // closest to a standard width or height being the cut with the maximum + // width. + EXPECT_EQ( + std::round(constraint_factory_.basic().width.max() / kIdealAspectRatio), + result.Height()); + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(1000); + constraint_factory_.basic().height.setMax(5000); + constraint_factory_.basic().width.setMin(1000); + constraint_factory_.basic().width.setMax(5000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal aspect-ratio is included in the bounding box, with the value + // closest to a standard width or height and largest area being the cut with + // the minimum height. + EXPECT_EQ(constraint_factory_.basic().height.min(), result.Height()); + EXPECT_EQ(std::round(constraint_factory_.basic().height.min() * + kIdealAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().height.setMin(250); + constraint_factory_.basic().height.setMax(5000); + constraint_factory_.basic().width.setMin(250); + constraint_factory_.basic().width.setMax(5000); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal aspect-ratio and default width and height are included in the + // bounding box. Preserving default height leads to larger area than + // preserving default width. + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight * kIdealAspectRatio, + result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the constrained area, closest to min or max aspect ratio. + { + const double kMinAspectRatio = 0.5; + const double kMaxAspectRatio = 2.0; + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + constraint_factory_.basic().aspectRatio.setIdeal(3.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal is closest to kMaxAspectRatio. + EXPECT_EQ( + std::round(constraint_factory_.basic().width.max() / kMaxAspectRatio), + result.Height()); + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().aspectRatio.setIdeal(0.3); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal is closest to kMinAspectRatio. + EXPECT_EQ(constraint_factory_.basic().height.max(), result.Height()); + EXPECT_EQ( + std::round(constraint_factory_.basic().height.max() * kMinAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + + // Use a box that is bigger and further from the origin to force closeness + // to a different default dimension. + constraint_factory_.basic().height.setMin(1000); + constraint_factory_.basic().height.setMax(5000); + constraint_factory_.basic().width.setMin(1000); + constraint_factory_.basic().width.setMax(5000); + constraint_factory_.basic().aspectRatio.setIdeal(3.0); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal is closest to kMaxAspectRatio. + EXPECT_EQ(constraint_factory_.basic().height.min(), result.Height()); + EXPECT_EQ( + std::round(constraint_factory_.basic().height.min() * kMaxAspectRatio), + result.Width()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().aspectRatio.setIdeal(0.3); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal is closest to kMinAspectRatio. + EXPECT_EQ( + std::round(constraint_factory_.basic().width.min() / kMinAspectRatio), + result.Height()); + EXPECT_EQ(constraint_factory_.basic().width.min(), result.Width()); + CheckNonResolutionDefaults(result); + } + + // Ideal outside the constrained area, closest to a single point. + { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(100); + constraint_factory_.basic().height.setMax(500); + constraint_factory_.basic().width.setMin(100); + constraint_factory_.basic().width.setMax(500); + constraint_factory_.basic().aspectRatio.setMin(1.0); + constraint_factory_.basic().aspectRatio.setIdeal(10.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Ideal is closest to the min height and max width. + EXPECT_EQ(constraint_factory_.basic().height.min(), result.Height()); + EXPECT_EQ(constraint_factory_.basic().width.max(), result.Width()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryExactFrameRate) { + constraint_factory_.Reset(); + const int kFrameRate = 45.0; + constraint_factory_.basic().frameRate.setExact(kFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMinFrameRate) { + constraint_factory_.Reset(); + const double kFrameRate = 45.0; + constraint_factory_.basic().frameRate.setMin(kFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kFrameRate is greater that the default, so expect kFrameRate. + EXPECT_EQ(kFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + + const double kSmallFrameRate = 5.0; + constraint_factory_.basic().frameRate.setMin(kSmallFrameRate); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kFrameRate is greater that the default, so expect kFrameRate. + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryMaxFrameRate) { + constraint_factory_.Reset(); + const double kFrameRate = 45.0; + constraint_factory_.basic().frameRate.setMax(kFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kFrameRate is greater that the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + + const double kSmallFrameRate = 5.0; + constraint_factory_.basic().frameRate.setMax(kSmallFrameRate); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kFrameRate is less that the default, so expect kFrameRate. + EXPECT_EQ(kSmallFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, MandatoryRangeFrameRate) { + constraint_factory_.Reset(); + { + const double kMinFrameRate = 15.0; + const double kMaxFrameRate = 45.0; + constraint_factory_.basic().frameRate.setMax(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The range includes the default, so expect the default. + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } + + { + const double kMinFrameRate = 45.0; + const double kMaxFrameRate = 55.0; + constraint_factory_.basic().frameRate.setMax(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is greater that the default, so expect the minimum. + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } + + { + const double kMinFrameRate = 10.0; + const double kMaxFrameRate = 15.0; + constraint_factory_.basic().frameRate.setMax(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The whole range is less that the default, so expect the maximum. + EXPECT_EQ(kMaxFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, IdealFrameRate) { + // Unconstrained. + { + constraint_factory_.Reset(); + const int kIdealFrameRate = 45.0; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } + + // Ideal greater than maximum. + { + constraint_factory_.Reset(); + const int kIdealFrameRate = 45.0; + const int kMaxFrameRate = 30.0; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMaxFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } + + // Ideal less than minimum. + { + constraint_factory_.Reset(); + const int kIdealFrameRate = 45.0; + const int kMinFrameRate = 50.0; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + constraint_factory_.basic().frameRate.setMin(kMinFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kMinFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } + + // Ideal within range. + { + constraint_factory_.Reset(); + const int kIdealFrameRate = 45.0; + const int kMinFrameRate = 35.0; + const int kMaxFrameRate = 50.0; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + constraint_factory_.basic().frameRate.setMin(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(kIdealFrameRate, result.FrameRate()); + CheckNonFrameRateDefaults(result); + } +} + +// The "Advanced" tests check selection criteria involving advanced constraint +// sets. +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedMinMaxResolutionFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMin(2000000000); + advanced1.height.setMin(2000000000); + // The first advanced set cannot be satisfied and is therefore ignored in all + // calls to SelectSettings(). + // In this case, default settings must be selected. + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.height.setMax(400); + advanced2.width.setMax(500); + advanced2.aspectRatio.setExact(5.0 / 4.0); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(400, result.Height()); + EXPECT_EQ(500, result.Width()); + CheckNonResolutionDefaults(result); + + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.frameRate.setMax(10.0); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The third advanced set is supported in addition to the previous set. + EXPECT_EQ(400, result.Height()); + EXPECT_EQ(500, result.Width()); + EXPECT_EQ(10.0, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); + + blink::WebMediaTrackConstraintSet& advanced4 = + constraint_factory_.AddAdvanced(); + advanced4.width.setExact(1000); + advanced4.height.setExact(1000); + result = SelectSettings(); + // The fourth advanced set cannot be supported in combination with the + // previous two sets, so it must be ignored. + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(400, result.Height()); + EXPECT_EQ(500, result.Width()); + EXPECT_EQ(10.0, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); + + constraint_factory_.basic().width.setIdeal(100); + constraint_factory_.basic().height.setIdeal(100); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The closest point to (100, 100) that satisfies all previous constraint + // sets is its projection on the aspect-ratio line 5.0/4.0. + // This is a point m*(4, 5) such that Dot((4,5), (100 - m(4,5))) == 0. + // This works out to be m = 900/41. + EXPECT_EQ(std::round(4.0 * 900.0 / 41.0), result.Height()); + EXPECT_EQ(std::round(5.0 * 900.0 / 41.0), result.Width()); + EXPECT_EQ(10.0, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); + + constraint_factory_.basic().width.setIdeal(2000); + constraint_factory_.basic().height.setIdeal(1500); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The projection of (2000,1500) on the aspect-ratio line 5.0/4.0 is beyond + // the maximum of (400, 500), so use the maximum allowed resolution. + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(400, result.Height()); + EXPECT_EQ(500, result.Width()); + EXPECT_EQ(10.0, result.FrameRate()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); + EXPECT_EQ(std::string(), result.device_id()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedExactResolution) { + { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(40000000); + advanced1.height.setExact(40000000); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(300000000); + advanced2.height.setExact(300000000); + auto result = SelectSettings(); + // None of the constraint sets can be satisfied. Default resolution should + // be selected. + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + CheckNonResolutionDefaults(result); + + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.width.setExact(1920); + advanced3.height.setExact(1080); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + CheckNonResolutionDefaults(result); + + blink::WebMediaTrackConstraintSet& advanced4 = + constraint_factory_.AddAdvanced(); + advanced4.width.setExact(640); + advanced4.height.setExact(480); + result = SelectSettings(); + // The fourth constraint set contradicts the third set. The fourth set + // should be ignored. + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + CheckNonResolutionDefaults(result); + + constraint_factory_.basic().width.setIdeal(800); + constraint_factory_.basic().height.setIdeal(600); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The exact constraints has priority over ideal. + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + CheckNonResolutionDefaults(result); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedResolutionAndFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(1920); + advanced1.height.setExact(1080); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.frameRate.setExact(60.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + EXPECT_EQ(60.0, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedNoiseReduction) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMin(640); + advanced1.height.setMin(480); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setMin(1920); + advanced2.height.setMin(1080); + advanced2.googNoiseReduction.setExact(false); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(1920, result.Width()); + // Preserves default aspect ratio. + EXPECT_EQ(static_cast<int>(std::round( + result.Width() / MediaStreamVideoSource::kDefaultAspectRatio)), + result.Height()); + EXPECT_TRUE(result.noise_reduction() && !*result.noise_reduction()); +} + +// The "AdvancedContradictory" tests check that advanced constraint sets that +// contradict previous constraint sets are ignored. +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryNoiseReduction) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(640); + advanced1.height.setExact(480); + advanced1.googNoiseReduction.setExact(true); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(1920); + advanced2.height.setExact(1080); + advanced2.googNoiseReduction.setExact(false); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(640, result.Width()); + EXPECT_EQ(480, result.Height()); + EXPECT_TRUE(result.noise_reduction() && *result.noise_reduction()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryExactResolution) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(640); + advanced1.height.setExact(480); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(1920); + advanced2.height.setExact(1080); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(640, result.Width()); + EXPECT_EQ(480, result.Height()); + // Resolution cannot be adjusted due to exact in the first advanced set. + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryMaxMinResolutionFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMax(640); + advanced1.height.setMax(480); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setMin(1920); + advanced2.height.setMin(1080); + advanced2.frameRate.setExact(60.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(640, result.Width()); + EXPECT_EQ(480, result.Height()); + // Resolution cannot exceed the requested resolution. + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryMinMaxResolutionFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMin(800); + advanced1.height.setMin(600); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setMax(640); + advanced2.height.setMax(480); + advanced2.frameRate.setExact(60.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(800, result.Width()); + EXPECT_EQ(600, result.Height()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultFrameRate, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryExactAspectRatio) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.aspectRatio.setExact(10.0); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.aspectRatio.setExact(3.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(std::round(MediaStreamVideoSource::kDefaultHeight * 10.0), + result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryAspectRatioRange) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.aspectRatio.setMin(10.0); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.aspectRatio.setMax(3.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(std::round(MediaStreamVideoSource::kDefaultHeight * 10.0), + result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + CheckNonResolutionDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryExactFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.frameRate.setExact(40.0); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.frameRate.setExact(45.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(40.0, result.FrameRate()); + CheckNonFrameRateDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryFrameRateRange) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.frameRate.setMin(40.0); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.frameRate.setMax(35.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_LE(40.0, result.FrameRate()); + CheckNonFrameRateDefaults(result); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryWidthFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMax(1920); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setMin(2000); + advanced2.frameRate.setExact(10.0); + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.frameRate.setExact(90.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(90.0, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryHeightFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.height.setMax(1080); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.height.setMin(1500); + advanced2.frameRate.setExact(10.0); + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.frameRate.setExact(60.0); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + EXPECT_EQ(60.0, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedDeviceID) { + const std::string kDeviceID1 = "fake_device_1"; + const std::string kDeviceID2 = "fake_device_2"; + const std::string kDeviceID3 = "fake_device_3"; + const std::string kDeviceID4 = "fake_device_4"; + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + blink::WebString id_vector1[] = {blink::WebString::fromASCII(kDeviceID1), + blink::WebString::fromASCII(kDeviceID2)}; + advanced1.deviceId.setExact( + blink::WebVector<blink::WebString>(id_vector1, arraysize(id_vector1))); + blink::WebString id_vector2[] = {blink::WebString::fromASCII(kDeviceID2), + blink::WebString::fromASCII(kDeviceID3)}; + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.deviceId.setExact( + blink::WebVector<blink::WebString>(id_vector2, arraysize(id_vector2))); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // kDeviceID2 must be selected because it is the only one that satisfies both + // advanced sets. + EXPECT_EQ(kDeviceID2, result.device_id()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, + AdvancedContradictoryDeviceID) { + const std::string kDeviceID1 = "fake_device_1"; + const std::string kDeviceID2 = "fake_device_2"; + const std::string kDeviceID3 = "fake_device_3"; + const std::string kDeviceID4 = "fake_device_4"; + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + blink::WebString id_vector1[] = {blink::WebString::fromASCII(kDeviceID1), + blink::WebString::fromASCII(kDeviceID2)}; + advanced1.deviceId.setExact( + blink::WebVector<blink::WebString>(id_vector1, arraysize(id_vector1))); + blink::WebString id_vector2[] = {blink::WebString::fromASCII(kDeviceID3), + blink::WebString::fromASCII(kDeviceID4)}; + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.deviceId.setExact( + blink::WebVector<blink::WebString>(id_vector2, arraysize(id_vector2))); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The second advanced set must be ignored because it contradicts the first + // set. + EXPECT_EQ(std::string(kDeviceID1), result.device_id()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, AdvancedIdealDeviceID) { + const std::string kDeviceID1 = "fake_device_1"; + const std::string kDeviceID2 = "fake_device_2"; + const std::string kDeviceID3 = "fake_device_3"; + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced = + constraint_factory_.AddAdvanced(); + blink::WebString id_vector1[] = {blink::WebString::fromASCII(kDeviceID1), + blink::WebString::fromASCII(kDeviceID2)}; + advanced.deviceId.setExact( + blink::WebVector<blink::WebString>(id_vector1, arraysize(id_vector1))); + + blink::WebString id_vector2[] = {blink::WebString::fromASCII(kDeviceID2), + blink::WebString::fromASCII(kDeviceID3)}; + constraint_factory_.basic().deviceId.setIdeal( + blink::WebVector<blink::WebString>(id_vector2, arraysize(id_vector2))); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Should select kDeviceID2, which appears in ideal and satisfies the advanced + // set. + EXPECT_EQ(std::string(kDeviceID2), result.device_id()); +} + +TEST_F(MediaStreamConstraintsUtilVideoContentTest, ResolutionChangePolicy) { + { + constraint_factory_.Reset(); + auto result = SelectSettings(); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); + // Resolution can be adjusted. + EXPECT_EQ(media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setIdeal(630); + constraint_factory_.basic().height.setIdeal(470); + auto result = SelectSettings(); + EXPECT_EQ(630, result.Width()); + EXPECT_EQ(470, result.Height()); + // Resolution can be adjusted because ideal was used to select the + // resolution. + EXPECT_EQ(media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setExact(640); + constraint_factory_.basic().height.setExact(480); + auto result = SelectSettings(); + EXPECT_EQ(640, result.Width()); + EXPECT_EQ(480, result.Height()); + EXPECT_EQ(media::RESOLUTION_POLICY_FIXED_RESOLUTION, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setExact(1000); + constraint_factory_.basic().height.setExact(500); + auto result = SelectSettings(); + EXPECT_EQ(1000, result.Width()); + EXPECT_EQ(500, result.Height()); + EXPECT_EQ(media::RESOLUTION_POLICY_FIXED_RESOLUTION, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setExact(630); + constraint_factory_.basic().height.setExact(470); + auto result = SelectSettings(); + EXPECT_EQ(630, result.Width()); + EXPECT_EQ(470, result.Height()); + EXPECT_EQ(media::RESOLUTION_POLICY_FIXED_RESOLUTION, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setIdeal(630); + constraint_factory_.basic().width.setMin(629); + constraint_factory_.basic().width.setMax(631); + constraint_factory_.basic().height.setIdeal(470); + constraint_factory_.basic().height.setMin(469); + auto result = SelectSettings(); + EXPECT_EQ(630, result.Width()); + EXPECT_EQ(470, result.Height()); + // Min/Max ranges prevent the resolution from being adjusted. + EXPECT_EQ(media::RESOLUTION_POLICY_FIXED_RESOLUTION, + result.ResolutionChangePolicy()); + } + { + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setExact(1.32); + constraint_factory_.basic().height.setIdeal(480); + auto result = SelectSettings(); + EXPECT_EQ(std::round(480 * 1.32), result.Width()); + EXPECT_EQ(480, result.Height()); + // Exact aspect ratio prevents the resolution from being adjusted. + EXPECT_EQ(media::RESOLUTION_POLICY_FIXED_RESOLUTION, + result.ResolutionChangePolicy()); + } +} + +} // namespace content
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.cc b/content/renderer/media/media_stream_constraints_util_video_device.cc index 344ccd80..bfcaefe 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device.cc +++ b/content/renderer/media/media_stream_constraints_util_video_device.cc
@@ -174,15 +174,13 @@ VideoDeviceCaptureSourceSelectionResult ResultFromSettings( const VideoDeviceCaptureSourceSettings& settings) { - VideoDeviceCaptureSourceSelectionResult result; - result.capture_params.power_line_frequency = settings.power_line_frequency(); - result.capture_params.requested_format = settings.format(); - result.device_id = settings.device_id(); - result.facing_mode = settings.facing_mode(); - result.noise_reduction = settings.noise_reduction(); - result.failed_constraint_name = nullptr; + media::VideoCaptureParams capture_params; + capture_params.requested_format = settings.format(); + capture_params.power_line_frequency = settings.power_line_frequency(); - return result; + return VideoDeviceCaptureSourceSelectionResult( + settings.device_id(), settings.facing_mode(), capture_params, + settings.noise_reduction()); } // Generic distance function between two numeric values. Based on the fitness @@ -748,12 +746,26 @@ VideoDeviceCaptureCapabilities& VideoDeviceCaptureCapabilities::operator=( VideoDeviceCaptureCapabilities&& other) = default; -const char kDefaultFailedConstraintName[] = ""; - VideoDeviceCaptureSourceSelectionResult:: VideoDeviceCaptureSourceSelectionResult() - : failed_constraint_name(kDefaultFailedConstraintName), - facing_mode(::mojom::FacingMode::NONE) {} + : VideoDeviceCaptureSourceSelectionResult("") {} + +VideoDeviceCaptureSourceSelectionResult:: + VideoDeviceCaptureSourceSelectionResult(const char* failed_constraint_name) + : failed_constraint_name_(failed_constraint_name) {} + +VideoDeviceCaptureSourceSelectionResult:: + VideoDeviceCaptureSourceSelectionResult( + const std::string& device_id, + ::mojom::FacingMode facing_mode, + media::VideoCaptureParams capture_params, + rtc::Optional<bool> noise_reduction) + : failed_constraint_name_(nullptr), + device_id_(device_id), + facing_mode_(facing_mode), + capture_params_(capture_params), + noise_reduction_(noise_reduction) {} + VideoDeviceCaptureSourceSelectionResult:: VideoDeviceCaptureSourceSelectionResult( const VideoDeviceCaptureSourceSelectionResult& other) = default; @@ -793,7 +805,7 @@ kNumDefaultDistanceEntries); std::fill(best_distance.begin(), best_distance.end(), HUGE_VAL); VideoDeviceCaptureSourceSelectionResult result; - const char* failed_constraint_name = result.failed_constraint_name; + const char* failed_constraint_name = result.failed_constraint_name(); for (auto& device : capabilities.device_capabilities) { double basic_device_distance = @@ -884,7 +896,7 @@ } if (!result.HasValue()) - result.failed_constraint_name = failed_constraint_name; + return VideoDeviceCaptureSourceSelectionResult(failed_constraint_name); return result; }
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.h b/content/renderer/media/media_stream_constraints_util_video_device.h index 71a1925..02e47d7 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device.h +++ b/content/renderer/media/media_stream_constraints_util_video_device.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/logging.h" #include "content/common/content_export.h" #include "content/common/media/media_devices.mojom.h" #include "media/capture/video_capture_types.h" @@ -38,40 +39,86 @@ std::vector<rtc::Optional<bool>> noise_reduction_capabilities; }; -struct CONTENT_EXPORT VideoDeviceCaptureSourceSelectionResult { +class CONTENT_EXPORT VideoDeviceCaptureSourceSelectionResult { + public: + // Creates a result without value and with an empty failed constraint name. VideoDeviceCaptureSourceSelectionResult(); + + // Creates a result without value and with the given |failed_constraint_name|. + // Does not take ownership of |failed_constraint_name|, so it must be null or + // point to a string that remains accessible. + explicit VideoDeviceCaptureSourceSelectionResult( + const char* failed_constraint_name); + + // Creates a result with the given values. + VideoDeviceCaptureSourceSelectionResult( + const std::string& device_id, + ::mojom::FacingMode facing_mode_, + media::VideoCaptureParams capture_params_, + rtc::Optional<bool> noise_reduction_); + VideoDeviceCaptureSourceSelectionResult( const VideoDeviceCaptureSourceSelectionResult& other); + VideoDeviceCaptureSourceSelectionResult& operator=( + const VideoDeviceCaptureSourceSelectionResult& other); VideoDeviceCaptureSourceSelectionResult( VideoDeviceCaptureSourceSelectionResult&& other); + VideoDeviceCaptureSourceSelectionResult& operator=( + VideoDeviceCaptureSourceSelectionResult&& other); ~VideoDeviceCaptureSourceSelectionResult(); - VideoDeviceCaptureSourceSelectionResult& operator=( - const VideoDeviceCaptureSourceSelectionResult& other); - VideoDeviceCaptureSourceSelectionResult& operator=( - VideoDeviceCaptureSourceSelectionResult&& other); - bool HasValue() const { return failed_constraint_name == nullptr; } + bool HasValue() const { return failed_constraint_name_ == nullptr; } // Convenience accessors for fields embedded in |capture_params|. const media::VideoCaptureFormat& Format() const { - return capture_params.requested_format; + return capture_params_.requested_format; } int Width() const { - return capture_params.requested_format.frame_size.width(); + DCHECK(HasValue()); + return capture_params_.requested_format.frame_size.width(); } int Height() const { - return capture_params.requested_format.frame_size.height(); + DCHECK(HasValue()); + return capture_params_.requested_format.frame_size.height(); } - float FrameRate() const { return capture_params.requested_format.frame_rate; } + float FrameRate() const { + DCHECK(HasValue()); + return capture_params_.requested_format.frame_rate; + } media::PowerLineFrequency PowerLineFrequency() const { - return capture_params.power_line_frequency; + DCHECK(HasValue()); + return capture_params_.power_line_frequency; } - const char* failed_constraint_name; - std::string device_id; - ::mojom::FacingMode facing_mode; - media::VideoCaptureParams capture_params; - rtc::Optional<bool> noise_reduction; + // Other accessors. + const char* failed_constraint_name() const { return failed_constraint_name_; } + + const std::string& device_id() const { + DCHECK(HasValue()); + return device_id_; + } + + ::mojom::FacingMode facing_mode() const { + DCHECK(HasValue()); + return facing_mode_; + } + + const media::VideoCaptureParams& capture_params() const { + DCHECK(HasValue()); + return capture_params_; + } + + const rtc::Optional<bool>& noise_reduction() const { + DCHECK(HasValue()); + return noise_reduction_; + } + + private: + const char* failed_constraint_name_; + std::string device_id_; + ::mojom::FacingMode facing_mode_; + media::VideoCaptureParams capture_params_; + rtc::Optional<bool> noise_reduction_; }; // This function performs source and source-settings selection based on
diff --git a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc index 7e3a420..4222ea3 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc +++ b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
@@ -140,13 +140,13 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); // Should select the default device with closest-to-default settings. - EXPECT_EQ(default_device_->device_id, result.device_id); - EXPECT_EQ(default_device_->facing_mode, result.facing_mode); + EXPECT_EQ(default_device_->device_id, result.device_id()); + EXPECT_EQ(default_device_->facing_mode, result.facing_mode()); EXPECT_EQ(*default_closest_format_, result.Format()); // Should select default settings for other constraints. EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); - EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction()); } // The "Overconstrained" tests verify that failure of any single required @@ -158,7 +158,7 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().deviceId.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFacingMode) { @@ -169,7 +169,7 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().facingMode.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnVideoKind) { @@ -180,7 +180,7 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().videoKind.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnHeight) { @@ -189,21 +189,21 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().height.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().height.setMin(123467890); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().height.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().height.setMax(0); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().height.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnWidth) { @@ -212,21 +212,21 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().width.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().width.setMin(123467890); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().width.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().width.setMax(0); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().width.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -236,14 +236,14 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().aspectRatio.setMin(123467890.0); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); // This value is lower than the minimum supported by sources. @@ -252,7 +252,7 @@ result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFrameRate) { @@ -261,21 +261,21 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().frameRate.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().frameRate.setMin(123467890.0); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().frameRate.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().frameRate.setMax(0.0); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().frameRate.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -285,21 +285,21 @@ auto result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().googPowerLineFrequency.setMin(123467890); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), - result.failed_constraint_name); + result.failed_constraint_name()); constraint_factory_.Reset(); constraint_factory_.basic().googPowerLineFrequency.setMax(-1); result = SelectSettings(); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -327,7 +327,7 @@ SelectVideoDeviceCaptureSourceSettings(capabilities, constraints); EXPECT_FALSE(result.HasValue()); EXPECT_EQ(constraint_factory_.basic().googNoiseReduction.name(), - result.failed_constraint_name); + result.failed_constraint_name()); } // The "Mandatory" and "Ideal" tests check that various selection criteria work @@ -338,7 +338,7 @@ blink::WebString::fromASCII(default_device_->device_id)); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); @@ -346,7 +346,7 @@ constraint_factory_.basic().deviceId.setExact( blink::WebString::fromASCII(low_res_device_->device_id)); result = SelectSettings(); - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); @@ -354,7 +354,7 @@ constraint_factory_.basic().deviceId.setExact( blink::WebString::fromASCII(high_res_device_->device_id)); result = SelectSettings(); - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_closest_format_, result.Format()); EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); @@ -366,10 +366,10 @@ blink::WebString::fromASCII("environment")); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result.facing_mode); + EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result.facing_mode()); // Only the low-res device supports environment facing mode. Should select // default settings for everything else. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); @@ -378,10 +378,10 @@ blink::WebString::fromASCII("user")); result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(::mojom::FacingMode::USER, result.facing_mode); + EXPECT_EQ(::mojom::FacingMode::USER, result.facing_mode()); // Only the high-res device supports user facing mode. Should select default // settings for everything else. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_closest_format_, result.Format()); EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, result.PowerLineFrequency()); @@ -393,14 +393,14 @@ blink::WebString::fromASCII("depth")); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(kDeviceID4, result.device_id); + EXPECT_EQ(kDeviceID4, result.device_id()); EXPECT_EQ(media::PIXEL_FORMAT_Y16, result.Format().pixel_format); constraint_factory_.basic().videoKind.setExact( blink::WebString::fromASCII("color")); result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryPowerLineFrequency) { @@ -416,8 +416,8 @@ EXPECT_EQ(power_line_frequency, result.PowerLineFrequency()); // The default device and settings closest to the default should be // selected. - EXPECT_EQ(default_device_->device_id, result.device_id); - EXPECT_EQ(default_device_->facing_mode, result.facing_mode); + EXPECT_EQ(default_device_->device_id, result.device_id()); + EXPECT_EQ(default_device_->facing_mode, result.facing_mode()); EXPECT_EQ(*default_closest_format_, result.Format()); } } @@ -429,11 +429,11 @@ constraint_factory_.basic().googNoiseReduction.setExact(noise_reduction); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(noise_reduction, result.noise_reduction); + EXPECT_EQ(noise_reduction, result.noise_reduction()); // The default device and settings closest to the default should be // selected. - EXPECT_EQ(default_device_->device_id, result.device_id); - EXPECT_EQ(default_device_->facing_mode, result.facing_mode); + EXPECT_EQ(default_device_->device_id, result.device_id()); + EXPECT_EQ(default_device_->facing_mode, result.facing_mode()); EXPECT_EQ(*default_closest_format_, result.Format()); } } @@ -447,7 +447,7 @@ // All devices in |capabilities_| support the requested height. The algorithm // should prefer the first device that supports the requested height natively, // which is the low-res device. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(kHeight, result.Height()); const int kLargeHeight = 1500; @@ -456,7 +456,7 @@ EXPECT_TRUE(result.HasValue()); // Only the high-res device at the highest resolution supports the requested // height, even if not natively. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -468,7 +468,7 @@ EXPECT_TRUE(result.HasValue()); // All devices in |capabilities_| support the requested height range. The // algorithm should prefer the default device. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_LE(kHeight, result.Height()); const int kLargeHeight = 1500; @@ -477,7 +477,7 @@ EXPECT_TRUE(result.HasValue()); // Only the high-res device at the highest resolution supports the requested // height range. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -490,7 +490,7 @@ // All devices in |capabilities_| support the requested height range. The // algorithm should prefer the settings that natively exceed the requested // maximum by the lowest amount. In this case it is the low-res device. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(low_res_device_->formats[0], result.Format()); } @@ -509,7 +509,7 @@ // algorithm should prefer the default device since it has at least one // native format (the closest-to-default format) included in the requested // range. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -525,7 +525,7 @@ // In this case, the algorithm should prefer the low-res device since it is // the first device with a native format (800x600) included in the requested // range. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(800, result.Width()); EXPECT_EQ(600, result.Height()); } @@ -542,7 +542,7 @@ // In this case, the algorithm should prefer the high-res device since it is // the only device with a native format (1280x720) included in the requested // range. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); } @@ -557,7 +557,7 @@ EXPECT_TRUE(result.HasValue()); // The algorithm should select the first device that supports the ideal // height natively. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(kIdealHeight, result.Height()); } @@ -570,7 +570,7 @@ // ideal at a lower cost than the other devices (500 vs 600 or 720). // Note that a native resolution of 480 is further from the ideal than // 500 cropped to 480. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -582,7 +582,7 @@ // In this case, the high-res device has two configurations that satisfy // the ideal value (1920x1080 and 2304x1536). Select the one with shortest // native distance to the ideal value (1920x1080). - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1920, result.Width()); EXPECT_EQ(1080, result.Height()); } @@ -594,7 +594,7 @@ EXPECT_TRUE(result.HasValue()); // The algorithm must the select the only device that can satisfy the ideal, // which is the high-res device at the highest resolution. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } } @@ -608,7 +608,7 @@ // All devices in |capabilities_| support the requested width. The algorithm // should prefer the first device that supports the requested width natively, // which is the low-res device. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(kWidth, result.Width()); const int kLargeWidth = 2000; @@ -618,7 +618,7 @@ EXPECT_LE(kLargeWidth, result.Width()); // Only the high-res device at the highest resolution supports the requested // width, even if not natively. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -631,7 +631,7 @@ // All devices in |capabilities_| support the requested width range. The // algorithm should prefer the default device at 1000x1000, which is the // first configuration that satisfies the minimum width. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_LE(kWidth, result.Width()); EXPECT_EQ(1000, result.Width()); EXPECT_EQ(1000, result.Height()); @@ -642,7 +642,7 @@ EXPECT_TRUE(result.HasValue()); // Only the high-res device at the highest resolution supports the requested // minimum width. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_LE(kLargeWidth, result.Width()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -657,7 +657,7 @@ // algorithm should prefer the settings that natively exceed the requested // maximum by the lowest amount. In this case it is the low-res device at its // lowest resolution. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(low_res_device_->formats[0], result.Format()); } @@ -675,7 +675,7 @@ // All devices in |capabilities_| support the constraint range. The // algorithm should prefer the default device since it has at least one // native format (1000x1000) included in the requested range. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(1000, result.Width()); EXPECT_EQ(1000, result.Height()); } @@ -692,7 +692,7 @@ // In this case, the algorithm should prefer the low-res device since it is // the first device with a native format (800x600) included in the requested // range. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(800, result.Width()); EXPECT_EQ(600, result.Height()); } @@ -709,7 +709,7 @@ // In this case, the algorithm should prefer the high-res device since it is // the only device with a native format (1920x1080) included in the // requested range. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1920, result.Width()); EXPECT_EQ(1080, result.Height()); } @@ -724,7 +724,7 @@ EXPECT_TRUE(result.HasValue()); // The algorithm should select the first device that supports the ideal // width natively, which is the low-res device at 320x240. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(kIdealWidth, result.Width()); } @@ -737,7 +737,7 @@ // ideal at a lower cost than the other devices (500 vs 640). // Note that a native resolution of 320 is further from the ideal value of // 321 than 500 cropped to 321. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -747,7 +747,7 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); // The algorithm must the select the only device that can satisfy the ideal. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -758,7 +758,7 @@ EXPECT_TRUE(result.HasValue()); // The algorithm must the select the device and setting with less distance // to the ideal. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } } @@ -772,7 +772,7 @@ // All devices in |capabilities_| support the requested frame rate. The // algorithm should prefer the first device that supports the requested frame // rate natively, which is the low-res device at 640x480x30Hz. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(kFrameRate, result.FrameRate()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); @@ -784,7 +784,7 @@ // Only the high-res device supports the requested frame rate, even if not // natively. The least expensive configuration that supports the requested // frame rate is 1280x720x60Hz. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(60.0, result.FrameRate()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); @@ -798,7 +798,7 @@ EXPECT_TRUE(result.HasValue()); // All devices in |capabilities_| support the requested frame-rate range. The // algorithm should prefer the default device. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); // The format closest to the default satisfies the constraint. EXPECT_EQ(*default_closest_format_, result.Format()); @@ -808,7 +808,7 @@ EXPECT_TRUE(result.HasValue()); // Only the high-res device supports the requested frame-rate range. // The least expensive configuration is 1280x720x60Hz. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_LE(kLargeFrameRate, result.FrameRate()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); @@ -824,7 +824,7 @@ // algorithm should prefer the settings that natively exceed the requested // maximum by the lowest amount. In this case it is the high-res device with // default resolution . - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(kLowFrameRate, result.FrameRate()); EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); @@ -844,7 +844,7 @@ // All devices in |capabilities_| support the constraint range. The // algorithm should prefer the default device since its closest-to-default // format has a frame rate included in the requested range. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -860,7 +860,7 @@ // In this case, the algorithm should prefer the low-res device since it is // the first device with a native frame rate included in the requested // range. The default resolution should be preferred as secondary criterion. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); } @@ -877,7 +877,7 @@ // the only device with a native format included in the requested range. // The 1280x720 resolution should be selected due to closeness to default // settings, which is the second tie-breaker criterion that applies. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); } @@ -893,7 +893,7 @@ // The algorithm should select the first configuration that supports the // ideal frame rate natively, which is the low-res device. Default // resolution should be selected as secondary criterion. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); } @@ -906,7 +906,7 @@ // ideal at a lower cost than the other devices (40 vs 60). // Note that a native frame rate of 30 is further from the ideal than // 31 adjusted to 30. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -918,7 +918,7 @@ // The high-res device format 1280x720x60.0 must be selected because its // frame rate can satisfy the ideal frame rate and has resolution closest // to the default. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); EXPECT_EQ(60, result.FrameRate()); @@ -933,7 +933,7 @@ // The high-res device format 1280x720x60.0 must be selected because its // frame rate it closest to the ideal value and it has resolution closest to // the default. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); EXPECT_EQ(60, result.FrameRate()); @@ -958,7 +958,7 @@ // All devices in |capabilities_| support the requested aspect ratio. // The algorithm should prefer the first device that supports the requested // aspect ratio. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); const int kMinWidth = 500; @@ -981,7 +981,7 @@ EXPECT_LE(kAspectRatio, max_aspect_ratio); // The default device can support the requested aspect ratio with the default // settings (500x500) using cropping. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); const int kMinHeight = 480; @@ -1007,7 +1007,7 @@ // resolution of 640x480. Higher resolutions for the default device are more // penalized by the constraints than the default native resolution of the // low-res device. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); } @@ -1026,7 +1026,7 @@ // All devices in |capabilities_| support the requested aspect-ratio range. // The algorithm should prefer the first device that supports the requested // aspect-ratio range, which in this case is the default device. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); const int kMinWidth = 500; @@ -1052,7 +1052,7 @@ // resolution of 640x480. // Higher resolutions for the default device are more penalized by the // constraints than the default native resolution of the low-res device. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(*low_res_closest_format_, result.Format()); } @@ -1071,7 +1071,7 @@ // All devices in |capabilities_| support the requested aspect-ratio range. // The algorithm should prefer the first device that supports the requested // aspect-ratio range, which in this case is the default device. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); const int kExactWidth = 360; @@ -1095,7 +1095,7 @@ // The high-res device with a native resolution of 1280x720 can support // 360x720 with cropping with less penalty than the default device at // 1000x1000. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); } @@ -1123,7 +1123,7 @@ // All devices in |capabilities_| support the requested aspect-ratio range. // The algorithm should prefer the first device that supports the requested // aspect-ratio range, which in this case is the default device. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -1150,7 +1150,7 @@ EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); // The only device that supports the resolution and aspect ratio constraint // is the high-res device. The 1920x1080 is the least expensive format. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1920, result.Width()); EXPECT_EQ(1080, result.Height()); } @@ -1174,7 +1174,7 @@ // settings. EXPECT_LE(kIdealAspectRatio, max_aspect_ratio); EXPECT_GE(kIdealAspectRatio, min_aspect_ratio); - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); } @@ -1186,7 +1186,7 @@ // The only device that supports the ideal aspect ratio is the high-res // device. The least expensive way to support it with the 1920x1080 format // cropped to 1500x1. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1920, result.Width()); EXPECT_EQ(1080, result.Height()); } @@ -1198,7 +1198,7 @@ EXPECT_TRUE(result.HasValue()); // The only device that supports the ideal aspect ratio is the high-res // device with its highest resolution, cropped to 2000x1. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -1209,7 +1209,7 @@ EXPECT_TRUE(result.HasValue()); // The configuration closest to the ideal aspect ratio is is the high-res // device with its highest resolution, cropped to 2304x1. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -1222,7 +1222,7 @@ // The first device to support the ideal aspect ratio and the resolution // constraint is the low-res device. The 800x600 format cropped to 800x400 // is the lest expensive way to achieve it. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(800, result.Width()); EXPECT_EQ(600, result.Height()); } @@ -1236,7 +1236,7 @@ // The only device that supports the ideal aspect ratio and the resolution // constraint is the high-res device. The 1280x720 cropped to 1200x400 is // the lest expensive way to achieve it. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1280, result.Width()); EXPECT_EQ(720, result.Height()); } @@ -1255,7 +1255,7 @@ // set is therefore ignored in all calls to SelectSettings(). // Tie-breaker rule that applies is closeness to default settings. auto result = SelectSettings(); - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(*default_closest_format_, result.Format()); blink::WebMediaTrackConstraintSet& advanced2 = @@ -1267,7 +1267,7 @@ result = SelectSettings(); // The device that best supports this advanced set is the low-res device, // which natively supports the maximum resolution. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); @@ -1278,7 +1278,7 @@ EXPECT_TRUE(result.HasValue()); // The high-res device natively supports the third advanced set in addition // to the previous set and should be selected. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); @@ -1291,7 +1291,7 @@ // advanced natively, having better support for the previous sets has // precedence, so the high-res device is selected. EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); @@ -1305,7 +1305,7 @@ // precedence over the native fitness distance. // Both support standard fitness distance equally, since 600x400 can be // cropped to 320x240. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(600, result.Width()); EXPECT_EQ(400, result.Height()); @@ -1315,7 +1315,7 @@ EXPECT_TRUE(result.HasValue()); // The high-res device at 640x480@10Hz is closer to the large ideal // resolution. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); } @@ -1340,7 +1340,7 @@ // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 // satisfies sets 1, and 2. The latter must be selected, regardless of // any other criteria. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(1920, result.Width()); EXPECT_EQ(1080, result.Height()); EXPECT_EQ(60.0, result.FrameRate()); @@ -1359,10 +1359,10 @@ advanced2.googNoiseReduction.setExact(false); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_LE(1920, result.Width()); EXPECT_LE(1080, result.Height()); - EXPECT_TRUE(result.noise_reduction && !*result.noise_reduction); + EXPECT_TRUE(result.noise_reduction() && !*result.noise_reduction()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -1384,10 +1384,10 @@ // The second advanced set cannot be satisfied because it contradicts the // first set. The default device supports the first set and should be // selected. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_LE(640, result.Width()); EXPECT_LE(480, result.Height()); - EXPECT_TRUE(result.noise_reduction && *result.noise_reduction); + EXPECT_TRUE(result.noise_reduction() && *result.noise_reduction()); } // Same test without noise reduction @@ -1404,11 +1404,11 @@ auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); // Only the high-res device can satisfy the second advanced set. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_LE(1920, result.Width()); EXPECT_LE(1080, result.Height()); // Should select default noise reduction setting. - EXPECT_TRUE(!result.noise_reduction); + EXPECT_TRUE(!result.noise_reduction()); } } @@ -1428,7 +1428,7 @@ // The second advanced set must be ignored because it contradicts the first // set. The low-res device is the one that best supports the requested // resolution. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(640, result.Width()); EXPECT_EQ(480, result.Height()); } @@ -1451,7 +1451,7 @@ // set. The default device with the 200x200@40Hz format should be selected. // That format satisfies the first advanced set as well as any other, so the // tie breaker rule that applies is default device ID. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(200, result.Width()); EXPECT_EQ(200, result.Height()); EXPECT_EQ(40, result.FrameRate()); @@ -1475,7 +1475,7 @@ // set. The default device with the 1000x1000@20Hz format should be selected. // That format satisfies the first advanced set as well as any other, so the // tie breaker rule that applies is default device ID. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_EQ(1000, result.Width()); EXPECT_EQ(1000, result.Height()); EXPECT_EQ(20, result.FrameRate()); @@ -1495,7 +1495,7 @@ // The second advanced set must be ignored because it contradicts the first // set. Only the high-res device in the highest-resolution format supports the // requested aspect ratio. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -1513,7 +1513,7 @@ // The second advanced set must be ignored because it contradicts the first // set. Only the high-res device in the highest-resolution format supports the // requested aspect ratio. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(*high_res_highest_format_, result.Format()); } @@ -1567,7 +1567,7 @@ // The low-res device at 320x240@30Hz satisfies advanced sets 1 and 3. // The high-res device at 2304x1536@10.0f can satisfy sets 1 and 2, but not // both at the same time. Thus, low-res device must be preferred. - EXPECT_EQ(low_res_device_->device_id, result.device_id); + EXPECT_EQ(low_res_device_->device_id, result.device_id()); EXPECT_EQ(30.0, result.FrameRate()); EXPECT_GE(1920, result.Width()); } @@ -1591,7 +1591,7 @@ // sets 1 and 3. The same device at 2304x1536@10.0f can satisfy sets 1 and 2, // but not both at the same time. Thus, the format closest to default that // satisfies sets 1 and 3 must be chosen. - EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(high_res_device_->device_id, result.device_id()); EXPECT_EQ(60.0, result.FrameRate()); EXPECT_GE(1080, result.Height()); } @@ -1614,7 +1614,7 @@ EXPECT_TRUE(result.HasValue()); // kDeviceID2 must be selected because it is the only one that satisfies both // advanced sets. - EXPECT_EQ(std::string(kDeviceID2), result.device_id); + EXPECT_EQ(std::string(kDeviceID2), result.device_id()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -1636,7 +1636,7 @@ EXPECT_TRUE(result.HasValue()); // The second advanced set must be ignored because it contradicts the first // set. - EXPECT_EQ(std::string(kDeviceID1), result.device_id); + EXPECT_EQ(std::string(kDeviceID1), result.device_id()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, @@ -1658,7 +1658,7 @@ // The second advanced set cannot be satisfied because it contradicts the // first set. The default device supports the first set and should be // selected. - EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->device_id, result.device_id()); EXPECT_LE(640, result.Width()); EXPECT_LE(480, result.Height()); EXPECT_EQ(50, static_cast<int>(result.PowerLineFrequency())); @@ -1673,7 +1673,7 @@ auto result = SelectVideoDeviceCaptureSourceSettings( capabilities, constraint_factory_.CreateWebMediaConstraints()); EXPECT_FALSE(result.HasValue()); - EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); + EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, NoDevicesWithConstraints) { @@ -1683,7 +1683,7 @@ auto result = SelectVideoDeviceCaptureSourceSettings( capabilities, constraint_factory_.CreateWebMediaConstraints()); EXPECT_FALSE(result.HasValue()); - EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); + EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); } } // namespace content
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc index 0b8fb8c..15fc8ce 100644 --- a/content/renderer/media/user_media_client_impl.cc +++ b/content/renderer/media/user_media_client_impl.cc
@@ -394,7 +394,7 @@ const VideoDeviceCaptureSourceSelectionResult& selection_result) { DCHECK(CalledOnValidThread()); if (selection_result.HasValue()) { - controls->video.device_id = selection_result.device_id; + controls->video.device_id = selection_result.device_id(); } else { // TODO(guidou): Abort the request in all cases where |selection_result| // has no value, as the spec mandates. @@ -403,7 +403,7 @@ // devices. Fix once the standard behavior ceases to be disruptive. // See http://crbug.com/690491. blink::WebString failed_constraint_name = - blink::WebString::fromASCII(selection_result.failed_constraint_name); + blink::WebString::fromASCII(selection_result.failed_constraint_name()); blink::WebString device_id_constraint_name = blink::WebString::fromASCII( user_media_request.videoConstraints().basic().deviceId.name()); if (failed_constraint_name.equals(device_id_constraint_name)) {
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h index fd0cde4..5e7b341 100644 --- a/content/renderer/media/user_media_client_impl.h +++ b/content/renderer/media/user_media_client_impl.h
@@ -39,7 +39,7 @@ class MediaStreamAudioSource; class MediaStreamDispatcher; class MediaStreamVideoSource; -struct VideoDeviceCaptureSourceSelectionResult; +class VideoDeviceCaptureSourceSelectionResult; // UserMediaClientImpl is a delegate for the Media Stream GetUserMedia API. // It ties together WebKit and MediaStreamManager
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 1b58cf93..6fc1bc8 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1587,6 +1587,7 @@ "../renderer/media/media_stream_audio_unittest.cc", "../renderer/media/media_stream_constraints_util_sets_unittest.cc", "../renderer/media/media_stream_constraints_util_unittest.cc", + "../renderer/media/media_stream_constraints_util_video_content_unittest.cc", "../renderer/media/media_stream_constraints_util_video_device_unittest.cc", "../renderer/media/media_stream_dispatcher_unittest.cc", "../renderer/media/media_stream_video_capturer_source_unittest.cc",
diff --git a/content/test/data/gpu/functional_files/context.js b/content/test/data/gpu/functional_files/context.js index 90ba336..d89e722 100644 --- a/content/test/data/gpu/functional_files/context.js +++ b/content/test/data/gpu/functional_files/context.js
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Global variable. +// Global variables. var gl_context; +var gl_renderer; initializeWebGL = function(canvas) { gl_context = null; @@ -13,7 +14,7 @@ // If we don't have a GL context, give up now. if (!gl_context) { err = "Unable to initialize WebGL. Your browser may not support it."; - if (domAutomationController) { + if (window.domAutomationController) { console.log(err); } else { alert(err); @@ -34,8 +35,14 @@ gl_context.clearDepth(1); gl_context.clear(gl_context.COLOR_BUFFER_BIT | gl_context.DEPTH_BUFFER_BIT); + + // Also fetch the unmasked GL_RENDERER string. + var ext = gl_context.getExtension("WEBGL_debug_renderer_info"); + gl_renderer = gl_context.getParameter(ext.UNMASKED_RENDERER_WEBGL); } - domAutomationController.setAutomationId(0); - domAutomationController.send("FINISHED"); + if (window.domAutomationController) { + domAutomationController.setAutomationId(0); + domAutomationController.send("FINISHED"); + } }
diff --git a/content/test/data/loader/reload_test.html b/content/test/data/loader/reload_test.html new file mode 100644 index 0000000..feaf92c --- /dev/null +++ b/content/test/data/loader/reload_test.html
@@ -0,0 +1,6 @@ +<html> +<body> +<img src="empty16x16.png"> +<iframe src="simple_frame.html"></iframe> +</body> +</html>
diff --git a/content/test/data/loader/reload.html b/content/test/data/loader/simple_frame.html similarity index 100% rename from content/test/data/loader/reload.html rename to content/test/data/loader/simple_frame.html
diff --git a/content/test/fuzzer/BUILD.gn b/content/test/fuzzer/BUILD.gn index 4222577..e4459eda 100644 --- a/content/test/fuzzer/BUILD.gn +++ b/content/test/fuzzer/BUILD.gn
@@ -5,6 +5,7 @@ # Fuzzers for content/ components. import("//testing/libfuzzer/fuzzer_test.gni") +import("//third_party/protobuf/proto_library.gni") # Empty group for package discovery. group("fuzzer") { @@ -67,4 +68,22 @@ ] seed_corpus = "//content/test/data/fuzzer_corpus/clear_site_data/" } + + fuzzer_test("renderer_proto_tree_fuzzer") { + sources = [ + "renderer_proto_tree_fuzzer.cc", + ] + deps = [ + ":fuzzer_support", + ":html_tree_proto", + "//third_party/libprotobuf-mutator", + ] + } + + proto_library("html_tree_proto") { + sources = [ + "html_tree.proto", + ] + testonly = true + } }
diff --git a/content/test/fuzzer/DEPS b/content/test/fuzzer/DEPS new file mode 100644 index 0000000..bfe6240 --- /dev/null +++ b/content/test/fuzzer/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+third_party/libprotobuf-mutator/src/src", +] +
diff --git a/content/test/fuzzer/html_tree.proto b/content/test/fuzzer/html_tree.proto new file mode 100644 index 0000000..7e8e40a --- /dev/null +++ b/content/test/fuzzer/html_tree.proto
@@ -0,0 +1,252 @@ +syntax = "proto3"; + +message Document { + Tag root = 1; +} + +message Tag { + Name name = 1; + repeated Attribute attrs = 2; + repeated Tag subtags = 3; + + enum Name { + A = 0; + ABBR = 1; + ADDRESS = 2; + AREA = 3; + ARTICLE = 4; + ASIDE = 5; + AUDIO = 6; + B = 7; + BASE = 8; + BDI = 9; + BDO = 10; + BLOCKQUOTE = 11; + BODY = 12; + BR = 13; + BUTTON = 14; + CANVAS = 15; + CAPTION = 16; + CITE = 17; + CODE = 18; + COL = 19; + COLGROUP = 20; + DATA = 21; + DATALIST = 22; + DD = 23; + DEL = 24; + DFN = 25; + DIV = 26; + DL = 27; + DT = 28; + EM = 29; + EMBED = 30; + FIELDSET = 31; + FIGCAPTION = 32; + FIGURE = 33; + FOOTER = 34; + FORM = 35; + H1 = 36; + H2 = 37; + H3 = 38; + H4 = 39; + H5 = 40; + H6 = 41; + HEAD = 42; + HEADER = 43; + HR = 44; + HTML = 45; + I = 46; + IFRAME = 47; + IMG = 48; + INPUT = 49; + INS = 50; + KBD = 51; + KEYGEN = 52; + LABEL = 53; + LEGEND = 54; + LI = 55; + LINK = 56; + MAIN = 57; + MAP = 58; + MARK = 59; + META = 60; + METER = 61; + NAV = 62; + NOSCRIPT = 63; + OBJECT = 64; + OL = 65; + OPTGROUP = 66; + OPTION = 67; + OUTPUT = 68; + P = 69; + PARAM = 70; + PRE = 71; + PROGRESS = 72; + Q = 73; + RB = 74; + RP = 75; + RT = 76; + RTC = 77; + RUBY = 78; + S = 79; + SAMP = 80; + SCRIPT = 81; + SECTION = 82; + SELECT = 83; + SMALL = 84; + SOURCE = 85; + SPAN = 86; + STRONG = 87; + STYLE = 88; + SUB = 89; + SUP = 90; + TABLE = 91; + TBODY = 92; + TD = 93; + TEMPLATE = 94; + TEXTAREA = 95; + TFOOT = 96; + TH = 97; + THEAD = 98; + TIME = 99; + TITLE = 100; + TR = 101; + TRACK = 102; + U = 103; + UL = 104; + VAR = 105; + VIDEO = 106; + WBR = 107; + } +} + +message Attribute { + Name name = 1; + Value value = 2; + + message Value { + oneof value { + bool bool_value = 1; + uint64 uint_value = 2; + int64 int_value = 3; + double double_value = 4; + + int64 px_value = 5; + uint32 pct_value = 6; + } + } + + enum Name { + ACCEPT = 0; + ACCEPT_CHARSET = 1; + ACCESSKEY = 2; + ACTION = 3; + ALIGN = 4; + ALT = 5; + ASYNC = 6; + AUTOCOMPLETE = 7; + AUTOFOCUS = 8; + AUTOPLAY = 9; + AUTOSAVE = 10; + BGCOLOR = 11; + BORDER = 12; + BUFFERED = 13; + CHALLENGE = 14; + CHARSET = 15; + CHECKED = 16; + CITE = 17; + CLASS = 18; + CODE = 19; + CODEBASE = 20; + COLOR = 21; + COLS = 22; + COLSPAN = 23; + CONTENT = 24; + CONTENTEDITABLE = 25; + CONTEXTMENU = 26; + CONTROLS = 27; + DATA = 28; + DATETIME = 29; + DEFAULT = 30; + DEFER = 31; + DIR = 32; + DIRNAME = 33; + DISABLED = 34; + DOWNLOAD = 35; + DRAGGABLE = 36; + DROPZONE = 37; + ENCTYPE = 38; + FOR = 39; + FORM = 40; + FORMACTION = 41; + HEADERS = 42; + HEIGHT = 43; + HIDDEN = 44; + HIGH = 45; + HREF = 46; + HREFLANG = 47; + ICON = 48; + ID = 49; + ISMAP = 50; + ITEMPROP = 51; + KEYTYPE = 52; + KIND = 53; + LABEL = 54; + LANG = 55; + LANGUAGE = 56; + LIST = 57; + LOOP = 58; + LOW = 59; + MANIFEST = 60; + MAX = 61; + MAXLENGTH = 62; + MEDIA = 63; + METHOD = 64; + MIN = 65; + MULTIPLE = 66; + MUTED = 67; + NAME = 68; + NOVALIDATE = 69; + OPEN = 70; + OPTIMUM = 71; + PATTERN = 72; + PING = 73; + PLACEHOLDER = 74; + POSTER = 75; + PRELOAD = 76; + RADIOGROUP = 77; + READONLY = 78; + REL = 79; + REQUIRED = 80; + REVERSED = 81; + ROWS = 82; + ROWSPAN = 83; + SANDBOX = 84; + SCOPE = 85; + SCOPED = 86; + SEAMLESS = 87; + SELECTED = 88; + SHAPE = 89; + SIZE = 90; + SIZES = 91; + SPAN = 92; + SPELLCHECK = 93; + SRC = 94; + SRCDOC = 95; + SRCLANG = 96; + SRCSET = 97; + START = 98; + STEP = 99; + STYLE = 100; + SUMMARY = 101; + TABINDEX = 102; + TARGET = 103; + TITLE = 104; + TYPE = 105; + USEMAP = 106; + VALUE = 107; + WIDTH = 108; + WRAP = 109; + } +}
diff --git a/content/test/fuzzer/renderer_proto_tree_fuzzer.cc b/content/test/fuzzer/renderer_proto_tree_fuzzer.cc new file mode 100644 index 0000000..1a71c04c --- /dev/null +++ b/content/test/fuzzer/renderer_proto_tree_fuzzer.cc
@@ -0,0 +1,144 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Fuzzer for content/renderer + +#include <stddef.h> +#include <stdint.h> +#include <memory> +#include <sstream> + +#include "content/test/fuzzer/fuzzer_support.h" +#include "content/test/fuzzer/html_tree.pb.h" +#include "third_party/libprotobuf-mutator/src/src/binary_format.h" +#include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_mutator.h" + +protobuf_mutator::protobuf::LogSilencer log_silincer; + +namespace content { + +class HtmlTreeWriter { + public: + HtmlTreeWriter() {} + + template <typename T> + HtmlTreeWriter& operator<<(const T& t) { + out_ << t; + return *this; + } + + std::string str() const { return out_.str(); } + + private: + std::ostringstream out_; +}; + +static HtmlTreeWriter& operator<<(HtmlTreeWriter& w, + const Attribute::Value& value) { + switch (value.value_case()) { + case Attribute::Value::kBoolValue: + return w << (value.bool_value() ? "true" : "false"); + case Attribute::Value::kUintValue: + return w << value.uint_value(); + case Attribute::Value::kIntValue: + return w << value.int_value(); + case Attribute::Value::kDoubleValue: + return w << value.double_value(); + case Attribute::Value::kPxValue: + return w << value.px_value() << "px"; + case Attribute::Value::kPctValue: + return w << value.pct_value() << "%"; + case Attribute::Value::VALUE_NOT_SET: + return w; + } +} + +static HtmlTreeWriter& operator<<(HtmlTreeWriter& w, + const Attribute::Name& name) { + return w << Attribute_Name_Name(name); +} + +static HtmlTreeWriter& operator<<(HtmlTreeWriter& w, const Attribute& attr) { + return w << attr.name() << "=\"" << attr.value() << "\""; +} + +static HtmlTreeWriter& operator<<(HtmlTreeWriter& w, const Tag::Name& tagName) { + return w << Tag_Name_Name(tagName); +} + +static void operator<<(HtmlTreeWriter& w, const Tag& tag) { + w << "<" << tag.name(); + for (const auto& attr : tag.attrs()) { + w << " " << attr; + } + + w << ">"; + for (const auto& subtag : tag.subtags()) { + w << subtag; + } + w << "</" << tag.name() << ">"; +} + +static void operator<<(HtmlTreeWriter& w, const Document& document) { + w << document.root(); +} + +static std::string str(const uint8_t* data, size_t size) { + Document document; + protobuf_mutator::ParseBinaryMessage(data, size, &document); + + HtmlTreeWriter writer; + writer << document; + return writer.str(); + // return document.ShortDebugString(); +} + +extern "C" void LLVMPrintInput(const uint8_t* data, size_t size) { + // fprintf(stderr, "NEW %s\n", str(data, size).c_str()); +} + +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, + size_t size, + size_t max_size, + unsigned int seed) { + fprintf(stderr, "BEFORE %s\n", str(data, size).c_str()); + size_t new_size = protobuf_mutator::libfuzzer::MutateBinaryMessage<Document>( + data, size, max_size, seed); + fprintf(stderr, "AFTER %s\n", str(data, new_size).c_str()); + return new_size; +} + +extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t* data1, + size_t size1, + const uint8_t* data2, + size_t size2, + uint8_t* out, + size_t max_out_size, + unsigned int seed) { + fprintf(stderr, "BEFOR1 %s\n", str(data1, size1).c_str()); + fprintf(stderr, "BEFOR2 %s\n", str(data2, size2).c_str()); + size_t new_size = + protobuf_mutator::libfuzzer::CrossOverBinaryMessages<Document>( + data1, size1, data2, size2, out, max_out_size, seed); + fprintf(stderr, "AFTER %s\n", str(data1, new_size).c_str()); + return new_size; +} + +static Env* env = nullptr; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Environment has to be initialized in the same thread. + if (env == nullptr) + env = new Env(); + + // str(data, size); + + env->adapter->LoadHTML(str(data, size), "http://www.example.org"); + + // fprintf(stderr, "%s\n", writer.str().c_str()); + + return 0; +} + +} // namespace content
diff --git a/content/test/gpu/gpu_tests/gpu_process_expectations.py b/content/test/gpu/gpu_tests/gpu_process_expectations.py index 6a74f2b..b2f13df7 100644 --- a/content/test/gpu/gpu_tests/gpu_process_expectations.py +++ b/content/test/gpu/gpu_tests/gpu_process_expectations.py
@@ -20,7 +20,13 @@ # Chrome on Windows creates a GPU process that uses SwiftShader when using # either --disable-gpu or a blacklisted GPU. self.Skip('GpuProcess_no_gpu_process', ['win', 'debug'], bug=630728) - self.Skip('GpuProcess_skip_gpu_process', ['win', 'debug'], bug=630728) + self.Skip('GpuProcess_skip_gpu_process', ['win'], bug=630728) + + # Currently SwiftShader's integrated only on Windows. Remove + # platforms from this suppression as it is integrated on more + # platforms. + self.Skip('GpuProcess_swiftshader_for_webgl', + ['mac', 'linux', 'android', 'chromeos'], bug=630728) # There is no Android multi-gpu configuration and the helper # gpu_info_collector.cc::IdentifyActiveGPU is not even called.
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py index 39ab8718..247c952b 100644 --- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py +++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -110,12 +110,13 @@ ('GpuProcess_driver_bug_workarounds_upon_gl_renderer', 'chrome:gpu'), ('GpuProcess_only_one_workaround', 'chrome:gpu'), - ('GpuProcess_skip_gpu_process', 'chrome:gpu'), + ('GpuProcess_skip_gpu_process', 'gpu/functional_webgl.html'), ('GpuProcess_identify_active_gpu1', 'chrome:gpu'), ('GpuProcess_identify_active_gpu2', 'chrome:gpu'), ('GpuProcess_identify_active_gpu3', 'chrome:gpu'), ('GpuProcess_identify_active_gpu4', 'chrome:gpu'), - ('GpuProcess_disabling_workarounds_works', 'chrome:gpu')) + ('GpuProcess_disabling_workarounds_works', 'chrome:gpu'), + ('GpuProcess_swiftshader_for_webgl', 'gpu/functional_webgl.html')) # The earlier has_transparent_visuals_gpu_process and # no_transparent_visuals_gpu_process tests became no-ops in @@ -450,10 +451,15 @@ (recorded_disabled_gl_extensions, new_disabled_gl_extensions)) def _GpuProcess_skip_gpu_process(self, test_path): + # This test loads functional_webgl.html so that there is a + # deliberate attempt to use an API which would start the GPU + # process. On platforms where SwiftShader is used, this test + # should be skipped. Once SwiftShader is enabled on all platforms, + # this test should be removed. self.RestartBrowserIfNecessaryWithArgs([ '--disable-gpu', '--skip-gpu-data-loading']) - self._Navigate(test_path) + self._NavigateAndWait(test_path) if self.tab.EvaluateJavaScript('chrome.gpuBenchmarking.hasGpuProcess()'): self.fail('GPU process detected') @@ -523,6 +529,27 @@ if 'use_gpu_driver_workaround_for_testing' in workarounds: self.fail('use_gpu_driver_workaround_for_testing erroneously present') + def _GpuProcess_swiftshader_for_webgl(self, test_path): + # This test loads functional_webgl.html so that there is a + # deliberate attempt to use an API which would start the GPU + # process. On Windows, and eventually on other platforms where + # SwiftShader is used, this test should pass. + # + # TODO(kbr): figure out a better way than --disable-gpu to + # reliably trigger SwiftShader. + self.RestartBrowserIfNecessaryWithArgs(['--disable-gpu']) + self._NavigateAndWait(test_path) + # It looks like when SwiftShader is in use (via --disable-gpu), + # that GPU information collection doesn't yet contain what's + # expected (the system_info.gpu.aux_attributes['gl_renderer'] + # looks like it'll be null). Verified locally that we can fetch + # the desired information via WebGL. + renderer = self.tab.EvaluateJavaScript('gl_renderer') + if not renderer: + self.fail('getParameter(UNMASKED_RENDERER_WEBGL) was null') + if 'SwiftShader' not in renderer: + self.fail('Expected SwiftShader renderer; instead got ' + renderer) + def load_tests(loader, tests, pattern): del loader, tests, pattern # Unused. return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index db99f21..6f3f0f3 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -1002,11 +1002,20 @@ # Linux AMD R7 240 self.Fail('conformance2/textures/image_bitmap_from_video/' + + 'tex-2d-rgba16f-rgba-float.html', + ['linux', ('amd', 0x6613)], bug=701138) + self.Fail('conformance2/textures/image_bitmap_from_video/' + 'tex-2d-rgba16f-rgba-half_float.html', ['linux', ('amd', 0x6613)], bug=701138) self.Fail('conformance2/textures/image_bitmap_from_video/' + 'tex-2d-rgba32f-rgba-float.html', ['linux', ('amd', 0x6613)], bug=701138) + self.Fail('conformance2/textures/image_bitmap_from_video/' + + 'tex-2d-rgba4-rgba-unsigned_byte.html', + ['linux', ('amd', 0x6613)], bug=701138) + self.Fail('conformance2/textures/image_bitmap_from_video/' + + 'tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html', + ['linux', ('amd', 0x6613)], bug=701138) # Conflicting expectations to test that the # "Expectations have no collisions" unittest works.
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index 1f6128a08f..6c61b28 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -656,6 +656,11 @@ ['android', 'android-chromium', ('nvidia', 'NVIDIA Tegra')], bug=624621) + # NVIDIA Shield + self.Flaky('conformance/context/' + + 'context-eviction-with-garbage-collection.html', + ['android', ('nvidia', 'NVIDIA Tegra')], bug=701929) + ############ # ChromeOS # ############
diff --git a/content/test/gpu/run_gpu_integration_test.py b/content/test/gpu/run_gpu_integration_test.py index 16deb3ae..4845805 100755 --- a/content/test/gpu/run_gpu_integration_test.py +++ b/content/test/gpu/run_gpu_integration_test.py
@@ -5,6 +5,7 @@ import argparse import json +import os import sys from gpu_tests import path_util @@ -15,31 +16,47 @@ from telemetry.testing import browser_test_runner def PostprocessJSON(file_name, run_test_args): - def TrimPrefix(s): - return s[1 + s.rfind('.'):] - with open(file_name) as f: - test_result = json.load(f) - test_result['successes'] = map(TrimPrefix, test_result['successes']) - test_result['failures'] = map(TrimPrefix, test_result['failures']) - test_result['run_test_args'] = run_test_args - with open(file_name, 'w') as f: - json.dump(test_result, f) + # The file is not necessarily written depending on the arguments - only + # postprocess it in case it is. + if os.path.isfile(file_name): + with open(file_name) as f: + test_result = json.load(f) + test_result['run_test_args'] = run_test_args + with open(file_name, 'w') as f: + json.dump(test_result, f, indent=2) def main(): rest_args = sys.argv[1:] - retval = browser_test_runner.Run( - gpu_project_config.CONFIG, rest_args) - # Postprocess the outputted JSON to trim all of the prefixes from - # the test names, to keep them as similar to the old form as - # possible -- and keep them from getting crazily long. - parser = argparse.ArgumentParser(description='Temporary argument parser') + parser = argparse.ArgumentParser(description='Extra argument parser', + add_help=False) + parser.add_argument( - '--write-abbreviated-json-results-to', metavar='FILENAME', + '--write-run-test-arguments', + action='store_true', + help=('Write the test script arguments to the results file.')) + option, rest_args_filtered = parser.parse_known_args(rest_args) + + retval = browser_test_runner.Run( + gpu_project_config.CONFIG, rest_args_filtered) + + # We're not relying on argparse to print the help in the normal way, because + # we need the help output from both the argument parser here and the argument + # parser in browser_test_runner. + if '--help' in rest_args: + parser.print_help() + return retval + + # This duplicates an argument of browser_test_runner. + parser.add_argument( + '--write-full-results-to', metavar='FILENAME', action='store', - help=('Full path for json results')) + help=('If specified, writes the full results to that path.')) + option, _ = parser.parse_known_args(rest_args) - if option.write_abbreviated_json_results_to: - PostprocessJSON(option.write_abbreviated_json_results_to, rest_args) + + # Postprocess the outputted JSON to add test arguments. + if option.write_run_test_arguments and option.write_full_results_to: + PostprocessJSON(option.write_full_results_to, rest_args) return retval if __name__ == '__main__':
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h index 4a97d320..291adef 100644 --- a/device/bluetooth/bluetooth_adapter.h +++ b/device/bluetooth/bluetooth_adapter.h
@@ -101,7 +101,6 @@ // * IsConnecting() // * IsGattConnected() // * IsPaired() - // * IsTrustable() // // On Android and MacOS this method is called for each advertisement packet // received. On Chrome OS and Linux, we can't guarantee that this method
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc index 587fcb7c..665cbb6 100644 --- a/device/bluetooth/bluetooth_device.cc +++ b/device/bluetooth/bluetooth_device.cc
@@ -274,24 +274,12 @@ // Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001 if (type == BluetoothDeviceType::MOUSE && vendor == "7C:ED:8D") return false; - // Sony PlayStation Dualshock3 - if (IsTrustable()) - return false; // TODO: Move this database into a config file. return true; } -bool BluetoothDevice::IsTrustable() const { - // Sony PlayStation Dualshock3 - if ((GetVendorID() == 0x054c && GetProductID() == 0x0268 && - GetName() == std::string("PLAYSTATION(R)3 Controller"))) - return true; - - return false; -} - BluetoothDevice::UUIDSet BluetoothDevice::GetUUIDs() const { return device_uuids_.GetUUIDs(); }
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h index 8a5d063..8e9dedc 100644 --- a/device/bluetooth/bluetooth_device.h +++ b/device/bluetooth/bluetooth_device.h
@@ -252,10 +252,6 @@ bool IsPairable() const; // Indicates whether the device is paired with the adapter. - // On Chrome OS this function also returns true if the user has connected - // to the device in the past. - // TODO(crbug.com/649651): Change Chrome OS to only return true if the - // device is actually paired. virtual bool IsPaired() const = 0; // Indicates whether the device is currently connected to the adapter. @@ -278,10 +274,6 @@ // were called after the corresponding call to Connect(). virtual bool IsConnecting() const = 0; - // Indicates whether the device can be trusted, based on device properties, - // such as vendor and product id. - bool IsTrustable() const; - // Returns the set of UUIDs that this device supports. // * For classic Bluetooth devices this data is collected from both the EIR // data and SDP tables.
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc index 77ec31bf..1c40bbc 100644 --- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -669,14 +669,6 @@ // UMA connection counting if (property_name == properties->connected.name()) { - // PlayStation joystick tries to reconnect after disconnection from USB. - // If it is still not trusted, set it, so it becomes available on the - // list of known devices. - if (properties->connected.value()) { - if (device_bluez->IsTrustable() && !properties->trusted.value()) - device_bluez->SetTrusted(); - } - int count = 0; for (auto iter = devices_.begin(); iter != devices_.end(); ++iter) {
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc index 5db8d4fb..8d1b1e2 100644 --- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc +++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -2820,15 +2820,13 @@ kConnectedTrustedNotPairedDeviceAddress); ASSERT_TRUE(device != nullptr); - // On the DBus level the device is trusted but not paired. But the current - // implementation of |BluetoothDevice::IsPaired()| returns true in this case. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient:: kConnectedTrustedNotPairedDevicePath)); EXPECT_FALSE(properties->paired.value()); EXPECT_TRUE(properties->trusted.value()); - ASSERT_TRUE(device->IsPaired()); + ASSERT_FALSE(device->IsPaired()); // The |kConnectedTrustedNotPairedDevicePath| requests a passkey confirmation. // Obs.: This is the flow when CrOS triggers pairing with a iOS device.
diff --git a/device/bluetooth/bluez/bluetooth_device_bluez.cc b/device/bluetooth/bluez/bluetooth_device_bluez.cc index 8e09968..2df2d43 100644 --- a/device/bluetooth/bluez/bluetooth_device_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_device_bluez.cc
@@ -333,10 +333,11 @@ object_path_); DCHECK(properties); - // Trusted devices are devices that don't support pairing but that the - // user has explicitly connected; it makes no sense for UI purposes to - // treat them differently from each other. - return properties->paired.value() || properties->trusted.value(); + // The Paired property reflects the successful pairing for BR/EDR/LE. The + // value of the Paired property is always false for the devices that don't + // support pairing. Once a device is paired successfully, both Paired and + // Trusted properties will be set to true. + return properties->paired.value(); } bool BluetoothDeviceBlueZ::IsConnected() const { @@ -449,7 +450,7 @@ VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ << " in progress"; - if (IsPaired() || !pairing_delegate || !IsPairable()) { + if (IsPaired() || !pairing_delegate) { // No need to pair, or unable to, skip straight to connection. ConnectInternal(false, callback, error_callback); } else {
diff --git a/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java b/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java index 96508aa2..1ec65dee 100644 --- a/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java +++ b/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java
@@ -63,11 +63,13 @@ mNdef = ndef; } + @Override public void write(NdefMessage message) throws IOException, TagLostException, FormatException { mNdef.writeNdefMessage(message); } + @Override public NdefMessage read() throws IOException, TagLostException, FormatException { return mNdef.getNdefMessage(); } @@ -84,11 +86,13 @@ mNdefFormattable = ndefFormattable; } + @Override public void write(NdefMessage message) throws IOException, TagLostException, FormatException { mNdefFormattable.format(message); } + @Override public NdefMessage read() throws IOException, TagLostException, FormatException { return NfcTypeConverter.emptyNdefMessage(); }
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 3eaf1adc7..4c2c50ea 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -913,6 +913,7 @@ (gl_version_info_->IsAtLeastGLES(3, 1) || (gl_version_info_->IsAtLeastGL(3, 0) && extensions.Contains("GL_ARB_shading_language_420pack") && + extensions.Contains("GL_ARB_texture_storage") && extensions.Contains("GL_ARB_texture_gather") && extensions.Contains("GL_ARB_explicit_uniform_location") && extensions.Contains("GL_ARB_explicit_attrib_location") &&
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc index 4b9d7e43..e4cdd30 100644 --- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc +++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -25,7 +25,6 @@ is_in_gamma_correct_mode_(false), supports_usampler_(true), supports_r8_image_(true), - supports_r8_read_format_(true), is_gles31_compatible_(false), frame_id_(0), width_(0), @@ -59,67 +58,55 @@ is_gles31_compatible_ = decoder->GetGLContext()->GetVersionInfo()->IsAtLeastGLES(3, 1); - // Check if RGBA8UI is supported as an FBO colour target with depth. - // If not supported, GLSL needs to convert the data to/from float so there is - // a small extra cost. - { - GLuint rgba8ui_texture = 0, depth_texture = 0; - glGenTextures(1, &rgba8ui_texture); - glBindTexture(GL_TEXTURE_2D, rgba8ui_texture); - glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4); + if (is_gles31_compatible_) { + supports_r8_image_ = + decoder->GetGLContext()->HasExtension("GL_NV_image_formats"); - glGenTextures(1, &depth_texture); - glBindTexture(GL_TEXTURE_2D, depth_texture); - glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4); + // ES 3.0 requires GL_RGBA8UI is color renderable. + supports_usampler_ = true; + } else { + // CMAA requires GL_ARB_shader_image_load_store for GL, and it requires r8 + // image texture. + DCHECK(decoder->GetGLContext()->HasExtension( + "GL_ARB_shader_image_load_store")); + supports_r8_image_ = true; - // Create the FBO - GLuint rgba8ui_framebuffer = 0; - glGenFramebuffersEXT(1, &rgba8ui_framebuffer); - glBindFramebufferEXT(GL_FRAMEBUFFER, rgba8ui_framebuffer); + // Check if RGBA8UI is supported as an FBO colour target with depth. + // If not supported, GLSL needs to convert the data to/from float so there + // is a small extra cost. + { + glActiveTexture(GL_TEXTURE0); - // Bind to the FBO to test support - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, rgba8ui_texture, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, depth_texture, 0); - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); + GLuint rgba8ui_texture = 0, depth_texture = 0; + glGenTextures(1, &rgba8ui_texture); + glBindTexture(GL_TEXTURE_2D, rgba8ui_texture); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4); - supports_usampler_ = (status == GL_FRAMEBUFFER_COMPLETE); + glGenTextures(1, &depth_texture); + glBindTexture(GL_TEXTURE_2D, depth_texture); + glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4); - glDeleteFramebuffersEXT(1, &rgba8ui_framebuffer); - glDeleteTextures(1, &rgba8ui_texture); - glDeleteTextures(1, &depth_texture); - } + // Create the FBO + GLuint rgba8ui_framebuffer = 0; + glGenFramebuffersEXT(1, &rgba8ui_framebuffer); + glBindFramebufferEXT(GL_FRAMEBUFFER, rgba8ui_framebuffer); - // Check to see if R8 images are supported - // If not supported, images are bound as R32F for write targets, not R8. - { - GLuint r8_texture = 0; - glGenTextures(1, &r8_texture); - glBindTexture(GL_TEXTURE_2D, r8_texture); - glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_R8, 4, 4); + // Bind to the FBO to test support + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, rgba8ui_texture, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, depth_texture, 0); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); - glGetError(); // reset all previous errors - glBindImageTextureEXT(0, r8_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8); - if (glGetError() != GL_NO_ERROR) - supports_r8_image_ = false; + supports_usampler_ = (status == GL_FRAMEBUFFER_COMPLETE); - glDeleteTextures(1, &r8_texture); - } + glDeleteFramebuffersEXT(1, &rgba8ui_framebuffer); + glDeleteTextures(1, &rgba8ui_texture); + glDeleteTextures(1, &depth_texture); - // Check if R8 GLSL read formats are supported. - // If not supported, r32f is used instead. - { - const char shader_source[] = - SHADER(layout(r8) restrict writeonly uniform highp image2D g_r8Image; - void main() { - imageStore(g_r8Image, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 0.0)); - }); - - GLuint shader = CreateShader(GL_FRAGMENT_SHADER, "", shader_source); - supports_r8_read_format_ = (shader != 0); - if (shader != 0) { - glDeleteShader(shader); + decoder->RestoreTextureUnitBindings(0); + decoder->RestoreActiveTexture(); + decoder->RestoreFramebufferBindings(); } } @@ -128,9 +115,6 @@ VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: " << "Supports R8 Images is " << (supports_r8_image_ ? "true" : "false"); - VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: " - << "Supports R8 Read Format is " - << (supports_r8_read_format_ ? "true" : "false"); // Create the shaders std::ostringstream defines, edge1, edge2, combineEdges, blur, displayEdges, @@ -148,7 +132,7 @@ defines << "#define IN_GAMMA_CORRECT_MODE\n"; } - if (supports_r8_read_format_) { + if (supports_r8_image_) { defines << "#define EDGE_READ_FORMAT r8\n"; } else { defines << "#define EDGE_READ_FORMAT r32f\n"; @@ -629,7 +613,7 @@ const char header_es31[] = "#version 310 es \n"; - const char header_gl30[] = + const char header_gl130[] = "#version 130 \n" "#extension GL_ARB_shading_language_420pack : require \n" "#extension GL_ARB_texture_gather : require \n" @@ -637,14 +621,17 @@ "#extension GL_ARB_explicit_attrib_location : require \n" "#extension GL_ARB_shader_image_load_store : require \n"; - const char* header = NULL; + std::ostringstream header; if (is_gles31_compatible_) { - header = header_es31; + header << header_es31; + if (supports_r8_image_) + header << "#extension GL_NV_image_formats : require\n"; } else { - header = header_gl30; + header << header_gl130; } - const char* source_array[4] = {header, defines, "\n", source}; + std::string header_str = header.str(); + const char* source_array[4] = {header_str.c_str(), defines, "\n", source}; glShaderSource(shader, 4, source_array, NULL); glCompileShader(shader); @@ -821,42 +808,6 @@ return ret; } - uint PackZ(const uvec2 screenPos, const bool invertedZShape) { - uint retVal = screenPos.x | (screenPos.y << 15u); - if (invertedZShape) - retVal |= (1u << 30u); - return retVal; - } - - void UnpackZ(uint packedZ, out uvec2 screenPos, - out bool invertedZShape) - { - screenPos.x = packedZ & 0x7FFFu; - screenPos.y = (packedZ >> 15u) & 0x7FFFu; - invertedZShape = (packedZ >> 30u) == 1u; - } - - uint PackZ(const uvec2 screenPos, - const bool invertedZShape, - const bool horizontal) { - uint retVal = screenPos.x | (screenPos.y << 15u); - if (invertedZShape) - retVal |= (1u << 30u); - if (horizontal) - retVal |= (1u << 31u); - return retVal; - } - - void UnpackZ(uint packedZ, - out uvec2 screenPos, - out bool invertedZShape, - out bool horizontal) { - screenPos.x = packedZ & 0x7FFFu; - screenPos.y = (packedZ >> 15u) & 0x7FFFu; - invertedZShape = (packedZ & (1u << 30u)) != 0u; - horizontal = (packedZ & (1u << 31u)) != 0u; - } - vec4 PackBlurAAInfo(ivec2 pixelPos, uint shapeType) { uint packedEdges = uint( texelFetch(g_src0TextureFlt, pixelPos, 0).r * 255.5);
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h index f9bad67..9f2bd9ae 100644 --- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h +++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
@@ -57,7 +57,6 @@ bool is_in_gamma_correct_mode_; bool supports_usampler_; bool supports_r8_image_; - bool supports_r8_read_format_; bool is_gles31_compatible_; int frame_id_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 125ef53..6fb3fae 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -17603,7 +17603,6 @@ apply_framebuffer_attachment_cmaa_intel_.reset( new ApplyFramebufferAttachmentCMAAINTELResourceManager()); apply_framebuffer_attachment_cmaa_intel_->Initialize(this); - RestoreCurrentFramebufferBindings(); if (LOCAL_PEEK_GL_ERROR("glApplyFramebufferAttachmentCMAAINTEL") != GL_NO_ERROR) return;
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index 8ed8042..af5fb220 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -22,6 +22,10 @@ #include "ui/gl/gl_switches.h" #include "ui/gl/init/gl_factory.h" +#if defined(USE_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + namespace gpu { namespace { @@ -175,6 +179,14 @@ base::TimeTicks before_initialize_one_off = base::TimeTicks::Now(); +#if defined(USE_OZONE) + // Initialize Ozone GPU after the watchdog in case it hangs. The sandbox + // may also have started at this point. + ui::OzonePlatform::InitParams params; + params.single_process = false; + ui::OzonePlatform::InitializeForGPU(params); +#endif + // Load and initialize the GL implementation and locate the GL entry points if // needed. This initialization may have already happened if running in the // browser process, for example.
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 6a4a637..59a76ae8 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -3678,15 +3678,12 @@ Tab* newTab = [_preloadController releasePrerenderContents]; DCHECK(oldTab); DCHECK(newTab); - if (oldTab && newTab) { + bool canPruneItems = + [newTab navigationManager]->CanPruneAllButLastCommittedItem(); + if (oldTab && newTab && canPruneItems) { [oldTab recordStateInHistory]; - DCHECK([newTab navigationManager]); - CRWSessionController* newHistory = - [newTab navigationManagerImpl]->GetSessionController(); - DCHECK([oldTab navigationManager]); - CRWSessionController* oldHistory = - [oldTab navigationManagerImpl]->GetSessionController(); - [newHistory insertStateFromSessionController:oldHistory]; + [newTab navigationManager]->CopyStateFromAndPrune( + [oldTab navigationManager]); [[newTab nativeAppNavigationController] copyStateFrom:[oldTab nativeAppNavigationController]]; [_model replaceTab:oldTab withTab:newTab];
diff --git a/ios/web/navigation/crw_session_controller.h b/ios/web/navigation/crw_session_controller.h index 6fdd181..8e017a1 100644 --- a/ios/web/navigation/crw_session_controller.h +++ b/ios/web/navigation/crw_session_controller.h
@@ -41,6 +41,13 @@ @property(nonatomic, readonly, strong) CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; +// Whether the CRWSessionController can prune all but the last committed item. +// This is true when all the following conditions are met: +// - There is a last committed NavigationItem +// - There is not currently a pending history navigation +// - There is no transient NavigationItem. +@property(nonatomic, readonly) BOOL canPruneAllButLastCommittedItem; + // The ScopedNavigationItemImplList used to store the NavigationItemImpls for // this session. @property(nonatomic, readonly) const web::ScopedNavigationItemImplList& items; @@ -119,9 +126,18 @@ // Removes the pending and transient NavigationItems. - (void)discardNonCommittedItems; -// Inserts history state from |otherController| to the front of |items|. This -// function will create copies of |otherController|'s NavigationItems. -- (void)insertStateFromSessionController:(CRWSessionController*)otherController; +// Removes all items from this except the last committed item, and inserts +// copies of all items from |source| at the beginning of the session history. +// +// For example: +// source: A B *C* D +// this: E F *G* +// result: A B C *G* +// +// If there is a pending item after *G* in |this|, it is also preserved. +// This ignores any pending or transient entries in |source|. No-op if +// |canPruneAllButLastCommittedItem| is false. +- (void)copyStateFromSessionControllerAndPrune:(CRWSessionController*)source; // Sets |currentNavigationIndex_| to the |index| if it's in the entries bounds. - (void)goToItemAtIndex:(NSInteger)index;
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm index 1bb37874..e367d21b 100644 --- a/ios/web/navigation/crw_session_controller.mm +++ b/ios/web/navigation/crw_session_controller.mm
@@ -152,6 +152,11 @@ DCHECK(_pendingItemIndex == -1 || self.pendingItem); } +- (BOOL)canPruneAllButLastCommittedItem { + return self.currentNavigationIndex != -1 && self.pendingItemIndex == -1 && + !self.transientItem; +} + - (const web::ScopedNavigationItemImplList&)items { return _items; } @@ -486,35 +491,44 @@ _transientItem.reset(); } -- (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { - DCHECK(sourceSession); +- (void)copyStateFromSessionControllerAndPrune:(CRWSessionController*)source { + DCHECK(source); + if (!self.canPruneAllButLastCommittedItem) + return; // The other session may not have any items, in which case there is nothing - // to insert. The other session's currentItem will be bogus in such cases, so - // ignore it and return early. - web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items; + // to insert. + const web::ScopedNavigationItemImplList& sourceItems = source->_items; if (sourceItems.empty()) return; - // Cycle through the items from the other session and insert them before any - // items from this session. Do not copy anything that comes after the other - // session's current item. - NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; - for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { - std::unique_ptr<web::NavigationItemImpl> sourceItemCopy = - base::MakeUnique<web::NavigationItemImpl>(*sourceItems[i]); - _items.insert(_items.begin() + i, std::move(sourceItemCopy)); + // Early return if there's no committed source item. + if (!source.lastCommittedItem) + return; + + // Copy |sourceItems| into a new NavigationItemList. |mergedItems| is needs + // to be large enough for all items in |source| preceding + // |sourceCurrentIndex|, the |source|'s current item, and |self|'s current + // item, which comes out to |sourceCurrentIndex| + 2. + DCHECK_GT(source.currentNavigationIndex, -1); + size_t sourceCurrentIndex = + static_cast<size_t>(source.currentNavigationIndex); + web::ScopedNavigationItemImplList mergedItems(sourceCurrentIndex + 2); + for (size_t index = 0; index <= sourceCurrentIndex; ++index) { + mergedItems[index] = + base::MakeUnique<web::NavigationItemImpl>(*sourceItems[index]); } + mergedItems.back() = std::move(_items[self.currentNavigationIndex]); + + // Use |mergedItems| as the session history. + std::swap(mergedItems, _items); // Update state to reflect inserted NavigationItems. _previousNavigationIndex = -1; - _currentNavigationIndex += lastIndexToCopy + 1; - if (self.pendingItemIndex != -1) - self.pendingItemIndex += lastIndexToCopy + 1; + _currentNavigationIndex = self.items.size() - 1; DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), self.items.size()); - DCHECK(self.pendingItemIndex == -1 || self.pendingItem); } - (void)goToItemAtIndex:(NSInteger)index {
diff --git a/ios/web/navigation/crw_session_controller_unittest.mm b/ios/web/navigation/crw_session_controller_unittest.mm index 7c7d0177..087aa4b 100644 --- a/ios/web/navigation/crw_session_controller_unittest.mm +++ b/ios/web/navigation/crw_session_controller_unittest.mm
@@ -473,7 +473,7 @@ } // Tests inserting session controller state. -TEST_F(CRWSessionControllerTest, InsertState) { +TEST_F(CRWSessionControllerTest, CopyState) { // Add 1 committed and 1 pending item to target controller. [session_controller_ addPendingItem:GURL("http://www.url.com/2") @@ -504,8 +504,9 @@ initiationType:web::NavigationInitiationType::USER_INITIATED]; // Insert and verify the state of target session controller. + EXPECT_TRUE([session_controller_ canPruneAllButLastCommittedItem]); [session_controller_ - insertStateFromSessionController:other_session_controller.get()]; + copyStateFromSessionControllerAndPrune:other_session_controller.get()]; EXPECT_EQ(2U, [session_controller_ items].size()); EXPECT_EQ(1, [session_controller_ currentNavigationIndex]); @@ -521,7 +522,7 @@ } // Tests inserting session controller state from empty session controller. -TEST_F(CRWSessionControllerTest, InsertStateFromEmptySessionController) { +TEST_F(CRWSessionControllerTest, CopyStateFromEmptySessionController) { // Add 2 committed items to target controller. [session_controller_ addPendingItem:GURL("http://www.url.com/0") @@ -542,8 +543,9 @@ openedByDOM:NO]); // Insert and verify the state of target session controller. + EXPECT_TRUE([session_controller_ canPruneAllButLastCommittedItem]); [session_controller_ - insertStateFromSessionController:other_session_controller.get()]; + copyStateFromSessionControllerAndPrune:other_session_controller.get()]; EXPECT_EQ(2U, [session_controller_ items].size()); EXPECT_EQ(1, [session_controller_ currentNavigationIndex]); EXPECT_EQ(0, [session_controller_ previousNavigationIndex]); @@ -555,10 +557,12 @@ [session_controller_ URLForItemAtIndex:1]); } -// Tests inserting session controller state to empty session controller. -TEST_F(CRWSessionControllerTest, InsertStateToEmptySessionController) { - // Create source session controller with 2 committed items and one - // pending item. +// Tests that |-copyStateFromSessionControllerAndPrune:| is a no-op when the +// receiver has no last committed item. +TEST_F(CRWSessionControllerTest, CopyStateToEmptySessionController) { + EXPECT_FALSE([session_controller_ canPruneAllButLastCommittedItem]); + + // Create source session controller with 1 committed item. base::scoped_nsobject<CRWSessionController> other_session_controller( [[CRWSessionController alloc] initWithBrowserState:&browser_state_ openedByDOM:NO]); @@ -573,46 +577,35 @@ referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED initiationType:web::NavigationInitiationType::USER_INITIATED]; - [other_session_controller commitPendingItem]; - [other_session_controller - addPendingItem:GURL("http://www.url.com/2") - referrer:web::Referrer() - transition:ui::PAGE_TRANSITION_TYPED - initiationType:web::NavigationInitiationType::USER_INITIATED]; - // Insert and verify the state of target session controller. + // Attempt to copy |other_session_controller|'s state and verify that + // |session_controller_| is unchanged. [session_controller_ - insertStateFromSessionController:other_session_controller.get()]; - - EXPECT_EQ(2U, [session_controller_ items].size()); - EXPECT_EQ(1, [session_controller_ currentNavigationIndex]); + copyStateFromSessionControllerAndPrune:other_session_controller]; + EXPECT_TRUE([session_controller_ items].empty()); + EXPECT_EQ(-1, [session_controller_ currentNavigationIndex]); EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]); - EXPECT_EQ(-1, [session_controller_ pendingItemIndex]); + EXPECT_FALSE([session_controller_ currentItem]); EXPECT_FALSE([session_controller_ pendingItem]); - EXPECT_EQ(GURL("http://www.url.com/0"), - [session_controller_ URLForItemAtIndex:0]); - EXPECT_EQ(GURL("http://www.url.com/1"), - [session_controller_ URLForItemAtIndex:1]); + EXPECT_EQ(-1, [session_controller_ pendingItemIndex]); } -// Tests inserting session controller state. Verifies that pending item index -// remains valid. -TEST_F(CRWSessionControllerTest, - InsertStateWithPendingItemIndexInTargetController) { - // Add 2 committed items and make the first item pending. +// Tests that |-copyStateFromSessionControllerAndPrune:| is a no-op during a +// pending history navigation. +TEST_F(CRWSessionControllerTest, CopyStateDuringPendingHistoryNavigation) { + // Add 1 committed and 1 pending item to target controller. + [session_controller_ + addPendingItem:GURL("http://www.url.com/1") + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; + [session_controller_ commitPendingItem]; [session_controller_ addPendingItem:GURL("http://www.url.com/2") referrer:web::Referrer() transition:ui::PAGE_TRANSITION_TYPED initiationType:web::NavigationInitiationType::USER_INITIATED]; [session_controller_ commitPendingItem]; - [session_controller_ - addPendingItem:GURL("http://www.url.com/3") - referrer:web::Referrer() - transition:ui::PAGE_TRANSITION_TYPED - initiationType:web::NavigationInitiationType::USER_INITIATED]; - [session_controller_ commitPendingItem]; - [session_controller_ setPendingItemIndex:0]; // Create source session controller with 1 committed item. base::scoped_nsobject<CRWSessionController> other_session_controller( @@ -624,21 +617,76 @@ transition:ui::PAGE_TRANSITION_TYPED initiationType:web::NavigationInitiationType::USER_INITIATED]; [other_session_controller commitPendingItem]; + [other_session_controller + addPendingItem:GURL("http://www.url.com/1") + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; - // Insert and verify the state of target session controller. + // Set the pending item index to the first item. + [session_controller_ setPendingItemIndex:0]; + EXPECT_FALSE([session_controller_ canPruneAllButLastCommittedItem]); + + // Attempt to copy |other_session_controller|'s state and verify that + // |session_controller_| is unchanged. [session_controller_ - insertStateFromSessionController:other_session_controller.get()]; + copyStateFromSessionControllerAndPrune:other_session_controller]; + EXPECT_EQ(2U, [session_controller_ items].size()); + EXPECT_EQ(1, [session_controller_ currentNavigationIndex]); + EXPECT_EQ(0, [session_controller_ previousNavigationIndex]); + EXPECT_EQ(0, [session_controller_ pendingItemIndex]); + EXPECT_TRUE([session_controller_ pendingItem]); + EXPECT_EQ([session_controller_ previousItem], + [session_controller_ pendingItem]); +} - EXPECT_EQ(3U, [session_controller_ items].size()); - EXPECT_EQ(2, [session_controller_ currentNavigationIndex]); +// Tests that |-copyStateFromSessionControllerAndPrune:| is a when a transient +// NavigationItem exists. +TEST_F(CRWSessionControllerTest, CopyStateWithTransientItem) { + // Add 1 committed and 1 pending item to target controller. + [session_controller_ + addPendingItem:GURL("http://www.url.com/1") + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; + [session_controller_ commitPendingItem]; + GURL second_url = GURL("http://www.url.com/2"); + [session_controller_ + addPendingItem:second_url + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; + [session_controller_ addTransientItemWithURL:second_url]; + + // Create source session controller with 1 committed item. + base::scoped_nsobject<CRWSessionController> other_session_controller( + [[CRWSessionController alloc] initWithBrowserState:&browser_state_ + openedByDOM:NO]); + [other_session_controller + addPendingItem:GURL("http://www.url.com/0") + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; + [other_session_controller commitPendingItem]; + [other_session_controller + addPendingItem:GURL("http://www.url.com/1") + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + initiationType:web::NavigationInitiationType::USER_INITIATED]; + + // Attempt to copy |other_session_controller|'s state and verify that + // |session_controller_| is unchanged. + EXPECT_FALSE([session_controller_ canPruneAllButLastCommittedItem]); + [session_controller_ + copyStateFromSessionControllerAndPrune:other_session_controller]; + EXPECT_EQ(1U, [session_controller_ items].size()); + EXPECT_EQ(0, [session_controller_ currentNavigationIndex]); EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]); - EXPECT_EQ(1, [session_controller_ pendingItemIndex]); - EXPECT_EQ(GURL("http://www.url.com/0"), - [session_controller_ URLForItemAtIndex:0]); - EXPECT_EQ(GURL("http://www.url.com/2"), - [session_controller_ URLForItemAtIndex:1]); - EXPECT_EQ(GURL("http://www.url.com/2"), - [session_controller_ pendingItem]->GetURL()); + EXPECT_EQ(-1, [session_controller_ pendingItemIndex]); + EXPECT_TRUE([session_controller_ pendingItem]); + EXPECT_TRUE([session_controller_ transientItem]); + EXPECT_EQ([session_controller_ transientItem], + [session_controller_ currentItem]); } // Tests state of an empty session controller.
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h index 764ef58..56bd247 100644 --- a/ios/web/navigation/navigation_manager_impl.h +++ b/ios/web/navigation/navigation_manager_impl.h
@@ -144,6 +144,8 @@ void Reload(ReloadType reload_type, bool check_for_reposts) override; NavigationItemList GetBackwardItems() const override; NavigationItemList GetForwardItems() const override; + void CopyStateFromAndPrune(const NavigationManager* source) override; + bool CanPruneAllButLastCommittedItem() const override; void OverrideDesktopUserAgentForNextPendingItem() override; // Returns the current list of transient url rewriters, passing ownership to
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm index 9acc1412..41454efe 100644 --- a/ios/web/navigation/navigation_manager_impl.mm +++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -360,6 +360,18 @@ delegate_->GetWebState()->OpenURL(params); } +void NavigationManagerImpl::CopyStateFromAndPrune( + const NavigationManager* manager) { + DCHECK(manager); + CRWSessionController* other_session = + static_cast<const NavigationManagerImpl*>(manager)->session_controller_; + [session_controller_ copyStateFromSessionControllerAndPrune:other_session]; +} + +bool NavigationManagerImpl::CanPruneAllButLastCommittedItem() const { + return [session_controller_ canPruneAllButLastCommittedItem]; +} + std::unique_ptr<std::vector<BrowserURLRewriter::URLRewriter>> NavigationManagerImpl::GetTransientURLRewriters() { return std::move(transient_url_rewriters_);
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation_manager.h index 50bf82b..a8b1cf57 100644 --- a/ios/web/public/navigation_manager.h +++ b/ios/web/public/navigation_manager.h
@@ -166,6 +166,26 @@ virtual NavigationItemList GetBackwardItems() const = 0; virtual NavigationItemList GetForwardItems() const = 0; + // Removes all items from this except the last committed item, and inserts + // copies of all items from |source| at the beginning of the session history. + // + // For example: + // source: A B *C* D + // this: E F *G* + // result: A B C *G* + // + // If there is a pending item after *G* in |this|, it is also preserved. + // This ignores any pending or transient entries in |source|. This will be a + // no-op if called while CanPruneAllButLastCommittedItem() is false. + virtual void CopyStateFromAndPrune(const NavigationManager* source) = 0; + + // Whether the NavigationManager can prune all but the last committed item. + // This is true when all the following conditions are met: + // - There is a last committed NavigationItem. + // - There is no pending history navigation. + // - There is no transient NavigationItem. + virtual bool CanPruneAllButLastCommittedItem() const = 0; + // Forces the pending item to be loaded using desktop user agent. Note that // the pending item may or may not already exist. // TODO(crbug.com/692303): Remove this when overriding the user agent doesn't
diff --git a/ios/web/public/test/fakes/test_navigation_manager.h b/ios/web/public/test/fakes/test_navigation_manager.h index e0d6cc6a..53a7ef0a 100644 --- a/ios/web/public/test/fakes/test_navigation_manager.h +++ b/ios/web/public/test/fakes/test_navigation_manager.h
@@ -44,6 +44,8 @@ void Reload(ReloadType reload_type, bool check_for_reposts) override; NavigationItemList GetBackwardItems() const override; NavigationItemList GetForwardItems() const override; + void CopyStateFromAndPrune(const NavigationManager* source) override; + bool CanPruneAllButLastCommittedItem() const override; void OverrideDesktopUserAgentForNextPendingItem() override; // Setters for test data.
diff --git a/ios/web/public/test/fakes/test_navigation_manager.mm b/ios/web/public/test/fakes/test_navigation_manager.mm index 579a1e7..49cbc3b 100644 --- a/ios/web/public/test/fakes/test_navigation_manager.mm +++ b/ios/web/public/test/fakes/test_navigation_manager.mm
@@ -150,6 +150,16 @@ return NavigationItemList(); } +void TestNavigationManager::CopyStateFromAndPrune( + const NavigationManager* source) { + NOTREACHED(); +} + +bool TestNavigationManager::CanPruneAllButLastCommittedItem() const { + NOTREACHED(); + return false; +} + void TestNavigationManager::OverrideDesktopUserAgentForNextPendingItem() { NOTREACHED(); }
diff --git a/ios/web/webui/mojo_facade.h b/ios/web/webui/mojo_facade.h index 0e773088..f22d5b37 100644 --- a/ios/web/webui/mojo_facade.h +++ b/ios/web/webui/mojo_facade.h
@@ -10,7 +10,7 @@ #include <string> #import "base/ios/weak_nsobject.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" @protocol CRWJSInjectionEvaluator; @@ -133,7 +133,7 @@ // Id of the last created watch. int last_watch_id_; // Currently active watches created through this facade. - std::map<int, std::unique_ptr<mojo::Watcher>> watchers_; + std::map<int, std::unique_ptr<mojo::SimpleWatcher>> watchers_; }; } // web
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm index 651de5a..0761888 100644 --- a/ios/web/webui/mojo_facade.mm +++ b/ios/web/webui/mojo_facade.mm
@@ -252,16 +252,17 @@ int callback_id; CHECK(args->GetInteger("callbackId", &callback_id)); - mojo::Watcher::ReadyCallback callback = base::BindBlockArc(^( + mojo::SimpleWatcher::ReadyCallback callback = base::BindBlockArc(^( MojoResult result) { NSString* script = [NSString stringWithFormat:@"__crWeb.mojo.signalWatch(%d, %d)", callback_id, result]; [script_evaluator_ executeJavaScript:script completionHandler:nil]; }); - mojo::Watcher* watcher = new mojo::Watcher(FROM_HERE); + mojo::SimpleWatcher* watcher = new mojo::SimpleWatcher( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC); watchers_.insert(std::make_pair(++last_watch_id_, base::WrapUnique(watcher))); - watcher->Start(static_cast<mojo::Handle>(handle), signals, callback); + watcher->Watch(static_cast<mojo::Handle>(handle), signals, callback); return ValueFromInteger(last_watch_id_); }
diff --git a/ios/web/webui/mojo_facade_unittest.mm b/ios/web/webui/mojo_facade_unittest.mm index 542124c..cf7e512 100644 --- a/ios/web/webui/mojo_facade_unittest.mm +++ b/ios/web/webui/mojo_facade_unittest.mm
@@ -199,6 +199,18 @@ callback_id, MOJO_RESULT_OK]; [[[evaluator() expect] andDo:^(NSInvocation*) { callback_received = true; + + // Cancel the watch immediately to ensure there are no additional + // notifications. + NSDictionary* cancel_watch = @{ + @"name" : @"support.cancelWatch", + @"args" : @{ + @"watchId" : @(watch_id), + }, + }; + std::string result_as_string = + facade()->HandleMojoMessage(GetJson(cancel_watch)); + EXPECT_TRUE(result_as_string.empty()); }] executeJavaScript:expected_script completionHandler:nil]; // Write to the other end of the pipe.
diff --git a/ios/web/webui/web_ui_mojo_inttest.mm b/ios/web/webui/web_ui_mojo_inttest.mm index 64a3d1ea..cd69059 100644 --- a/ios/web/webui/web_ui_mojo_inttest.mm +++ b/ios/web/webui/web_ui_mojo_inttest.mm
@@ -7,6 +7,7 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #import "base/test/ios/wait_util.h" +#include "base/threading/thread_task_runner_handle.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_ui_ios_data_source.h" #include "ios/web/public/webui/web_ui_ios_controller.h" @@ -161,7 +162,16 @@ // Wait until |TestUIHandler| receives "ack" message from WebUI page. base::test::ios::WaitUntilCondition(^{ - base::RunLoop().RunUntilIdle(); + // Flush any pending tasks. Don't RunUntilIdle() because + // RunUntilIdle() is incompatible with mojo::SimpleWatcher's + // automatic arming behavior, which Mojo JS still depends upon. + // + // TODO(crbug.com/701875): Introduce the full watcher API to JS and get rid + // of this hack. + base::RunLoop loop; + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + loop.QuitClosure()); + loop.Run(); return test_ui_handler()->IsFinReceived(); }); }
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc index 840c89d9..6852399 100644 --- a/ipc/ipc_sync_channel.cc +++ b/ipc/ipc_sync_channel.cc
@@ -41,9 +41,9 @@ *error = result != MOJO_RESULT_OK; } -// A ReadyCallback for use with mojo::Watcher. Ignores the result (DCHECKs, but -// is only used in cases where failure should be impossible) and runs -// |callback|. +// A ReadyCallback for use with mojo::SimpleWatcher. Ignores the result +// (DCHECKs, but is only used in cases where failure should be impossible) and +// runs |callback|. void RunOnHandleReady(const base::Closure& callback, MojoResult result) { DCHECK_EQ(result, MOJO_RESULT_OK); callback.Run(); @@ -230,11 +230,11 @@ } } - mojo::Watcher* top_send_done_watcher() { + mojo::SimpleWatcher* top_send_done_watcher() { return top_send_done_watcher_; } - void set_top_send_done_watcher(mojo::Watcher* watcher) { + void set_top_send_done_watcher(mojo::SimpleWatcher* watcher) { top_send_done_watcher_ = watcher; } @@ -300,7 +300,7 @@ // The current send done handle watcher for this thread. Used to maintain // a thread-local stack of send done watchers to ensure that nested sync // message loops complete correctly. - mojo::Watcher* top_send_done_watcher_; + mojo::SimpleWatcher* top_send_done_watcher_; // If not null, the address of a flag to set when the dispatch event signals, // in lieu of actually dispatching messages. This is used by @@ -527,7 +527,8 @@ WaitableEvent* shutdown_event) : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)), sync_handle_registry_(mojo::SyncHandleRegistry::current()), - dispatch_watcher_(FROM_HERE) { + dispatch_watcher_(FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) { // The current (listener) thread must be distinct from the IPC thread, or else // sending synchronous messages will deadlock. DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get()); @@ -622,7 +623,6 @@ context->received_sync_msgs()->UnblockDispatch(); DCHECK(!error); - registry->UnregisterHandle(context->GetSendDoneEvent()->GetHandle()); if (pump_messages_event) registry->UnregisterHandle(pump_messages_event->GetHandle()); @@ -643,14 +643,15 @@ } void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) { - mojo::Watcher send_done_watcher(FROM_HERE); + mojo::SimpleWatcher send_done_watcher( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC); ReceivedSyncMsgQueue* sync_msg_queue = context->received_sync_msgs(); DCHECK_NE(sync_msg_queue, nullptr); - mojo::Watcher* old_watcher = sync_msg_queue->top_send_done_watcher(); + mojo::SimpleWatcher* old_watcher = sync_msg_queue->top_send_done_watcher(); mojo::Handle old_handle(mojo::kInvalidHandleValue); - mojo::Watcher::ReadyCallback old_callback; + mojo::SimpleWatcher::ReadyCallback old_callback; // Maintain a thread-local stack of watchers to ensure nested calls complete // in the correct sequence, i.e. the outermost call completes first, etc. @@ -664,7 +665,7 @@ { base::RunLoop nested_loop; - send_done_watcher.Start( + send_done_watcher.Watch( context->GetSendDoneEvent()->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&RunOnHandleReady, nested_loop.QuitClosure())); @@ -676,7 +677,7 @@ sync_msg_queue->set_top_send_done_watcher(old_watcher); if (old_watcher) - old_watcher->Start(old_handle, MOJO_HANDLE_SIGNAL_READABLE, old_callback); + old_watcher->Watch(old_handle, MOJO_HANDLE_SIGNAL_READABLE, old_callback); } void SyncChannel::OnDispatchHandleReady(MojoResult result) { @@ -690,10 +691,10 @@ // messages once the listener thread is unblocked and pumping its task queue. // The ReceivedSyncMsgQueue also watches this event and may dispatch // immediately if woken up by a message which it's allowed to dispatch. - dispatch_watcher_.Start(sync_context()->GetDispatchEvent()->GetHandle(), - MOJO_HANDLE_SIGNAL_READABLE, - base::Bind(&SyncChannel::OnDispatchHandleReady, - base::Unretained(this))); + dispatch_watcher_.Watch( + sync_context()->GetDispatchEvent()->GetHandle(), + MOJO_HANDLE_SIGNAL_READABLE, + base::Bind(&SyncChannel::OnDispatchHandleReady, base::Unretained(this))); } void SyncChannel::OnChannelInit() {
diff --git a/ipc/ipc_sync_channel.h b/ipc/ipc_sync_channel.h index e8c96d20..7738b7f 100644 --- a/ipc/ipc_sync_channel.h +++ b/ipc/ipc_sync_channel.h
@@ -19,7 +19,7 @@ #include "ipc/ipc_sync_message.h" #include "ipc/ipc_sync_message_filter.h" #include "mojo/public/c/system/types.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace base { class WaitableEvent; @@ -27,7 +27,6 @@ namespace mojo { class SyncHandleRegistry; -class Watcher; } namespace IPC { @@ -241,7 +240,7 @@ scoped_refptr<mojo::SyncHandleRegistry> sync_handle_registry_; // Used to signal events between the IPC and listener threads. - mojo::Watcher dispatch_watcher_; + mojo::SimpleWatcher dispatch_watcher_; // Tracks SyncMessageFilters created before complete channel initialization. std::vector<scoped_refptr<SyncMessageFilter>> pre_init_sync_message_filters_;
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java index 380068a..e942169 100644 --- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java +++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -701,6 +701,7 @@ return true; } + @Override public PhotoCapabilities getPhotoCapabilities() { final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mContext, mId); PhotoCapabilities.Builder builder = new PhotoCapabilities.Builder();
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc index 06233eaa..acccf2e 100644 --- a/media/filters/ffmpeg_audio_decoder.cc +++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -95,12 +95,17 @@ return buffer_size_in_bytes; int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; DCHECK_GE(frames_required, frame->nb_samples); + + ChannelLayout channel_layout = + ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); + + if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { + DLOG(ERROR) << "Unsupported channel layout."; + return AVERROR(EINVAL); + } + scoped_refptr<AudioBuffer> buffer = AudioBuffer::CreateBuffer( - sample_format, - ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels), - channels, - s->sample_rate, - frames_required); + sample_format, channel_layout, channels, s->sample_rate, frames_required); // Initialize the data[] and extended_data[] fields to point into the memory // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved
diff --git a/media/gpu/dxva_picture_buffer_win.cc b/media/gpu/dxva_picture_buffer_win.cc index 44f27f9..bcaa177 100644 --- a/media/gpu/dxva_picture_buffer_win.cc +++ b/media/gpu/dxva_picture_buffer_win.cc
@@ -370,6 +370,10 @@ return true; } +bool PbufferPictureBuffer::AllowOverlay() const { + return false; +} + PbufferPictureBuffer::PbufferPictureBuffer(const PictureBuffer& buffer) : DXVAPictureBuffer(buffer), decoding_surface_(NULL), @@ -508,6 +512,10 @@ return true; } +bool EGLStreamPictureBuffer::AllowOverlay() const { + return true; +} + EGLStreamCopyPictureBuffer::EGLStreamCopyPictureBuffer( const PictureBuffer& buffer) : DXVAPictureBuffer(buffer), stream_(nullptr) {} @@ -671,4 +679,8 @@ return true; } +bool EGLStreamCopyPictureBuffer::AllowOverlay() const { + return true; +} + } // namespace media
diff --git a/media/gpu/dxva_picture_buffer_win.h b/media/gpu/dxva_picture_buffer_win.h index ee4ce0c..29d502d1 100644 --- a/media/gpu/dxva_picture_buffer_win.h +++ b/media/gpu/dxva_picture_buffer_win.h
@@ -61,6 +61,11 @@ color_space_ = color_space; } + // Returns true if these could in theory be used as an overlay. May + // still be drawn using GL depending on the scene and precise hardware + // support. + virtual bool AllowOverlay() const = 0; + bool waiting_to_reuse() const { return state_ == WAITING_TO_REUSE; } virtual gl::GLFence* reuse_fence(); @@ -102,6 +107,7 @@ gl::GLFence* reuse_fence() override; bool CopySurfaceComplete(IDirect3DSurface9* src_surface, IDirect3DSurface9* dest_surface) override; + bool AllowOverlay() const override; protected: EGLSurface decoding_surface_; @@ -144,6 +150,7 @@ bool Initialize(); bool ReusePictureBuffer() override; bool BindSampleToTexture(base::win::ScopedComPtr<IMFSample> sample) override; + bool AllowOverlay() const override; private: EGLStreamKHR stream_; @@ -167,6 +174,7 @@ int input_buffer_id) override; bool CopySurfaceComplete(IDirect3DSurface9* src_surface, IDirect3DSurface9* dest_surface) override; + bool AllowOverlay() const override; private: EGLStreamKHR stream_;
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc index 3a36c38..a5d0ad9 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -2088,14 +2088,15 @@ void DXVAVideoDecodeAccelerator::NotifyPictureReady( int picture_buffer_id, int input_buffer_id, - const gfx::ColorSpace& color_space) { + const gfx::ColorSpace& color_space, + bool allow_overlay) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); // This task could execute after the decoder has been torn down. if (GetState() != kUninitialized && client_) { // TODO(henryhsu): Use correct visible size instead of (0, 0). We can't use // coded size here so use (0, 0) intentionally to have the client choose. Picture picture(picture_buffer_id, input_buffer_id, gfx::Rect(0, 0), - color_space, false); + color_space, allow_overlay); client_->PictureReady(picture); } } @@ -2506,7 +2507,8 @@ PLATFORM_FAILURE, ); NotifyPictureReady(picture_buffer->id(), input_buffer_id, - picture_buffer->color_space()); + picture_buffer->color_space(), + picture_buffer->AllowOverlay()); { base::AutoLock lock(decoder_lock_); @@ -2559,7 +2561,8 @@ PLATFORM_FAILURE, ); NotifyPictureReady(picture_buffer->id(), input_buffer_id, - picture_buffer->color_space()); + picture_buffer->color_space(), + picture_buffer->AllowOverlay()); { base::AutoLock lock(decoder_lock_);
diff --git a/media/gpu/dxva_video_decode_accelerator_win.h b/media/gpu/dxva_video_decode_accelerator_win.h index 6422f63f..9637845 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.h +++ b/media/gpu/dxva_video_decode_accelerator_win.h
@@ -241,7 +241,8 @@ // Notifies the client about the availability of a picture. void NotifyPictureReady(int picture_buffer_id, int input_buffer_id, - const gfx::ColorSpace& color_space); + const gfx::ColorSpace& color_space, + bool allow_overlay); // Sends pending input buffer processed acks to the client if we don't have // output samples waiting to be processed.
diff --git a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc index 9ed0624..cb61aced 100644 --- a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc +++ b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
@@ -450,7 +450,7 @@ texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, GL_RGBA, texture_dimensions_.width(), texture_dimensions_.height(), 1, 0, - GL_RGBA, 0, gfx::Rect()); + GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect()); } else { // For other targets, texture dimensions should already be defined. GLsizei width = 0, height = 0; @@ -467,9 +467,10 @@ GLenum format = video_decode_accelerator_.get()->GetSurfaceInternalFormat(); if (format != GL_RGBA) { + DCHECK(format == GL_BGRA_EXT); texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format, - width, height, 1, 0, format, 0, - gfx::Rect()); + width, height, 1, 0, format, + GL_UNSIGNED_BYTE, gfx::Rect()); } } service_ids.push_back(texture_ref->service_id());
diff --git a/media/mojo/common/mojo_decoder_buffer_converter.cc b/media/mojo/common/mojo_decoder_buffer_converter.cc index 32080d3..d47e5f5 100644 --- a/media/mojo/common/mojo_decoder_buffer_converter.cc +++ b/media/mojo/common/mojo_decoder_buffer_converter.cc
@@ -64,18 +64,20 @@ MojoDecoderBufferReader::MojoDecoderBufferReader( mojo::ScopedDataPipeConsumerHandle consumer_handle) : consumer_handle_(std::move(consumer_handle)), - pipe_watcher_(FROM_HERE), + pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL), bytes_read_(0) { DVLOG(1) << __func__; MojoResult result = - pipe_watcher_.Start(consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, + pipe_watcher_.Watch(consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&MojoDecoderBufferReader::OnPipeReadable, base::Unretained(this))); if (result != MOJO_RESULT_OK) { DVLOG(1) << __func__ << ": Failed to start watching the pipe. result=" << result; consumer_handle_.reset(); + } else { + pipe_watcher_.ArmOrNotify(); } } @@ -159,13 +161,16 @@ if (IsPipeReadWriteError(result)) { OnPipeError(result); - } else if (result == MOJO_RESULT_OK) { - DCHECK_GT(num_bytes, 0u); - bytes_read_ += num_bytes; - if (bytes_read_ == buffer_size) { - DCHECK(read_cb_); - bytes_read_ = 0; - std::move(read_cb_).Run(std::move(media_buffer_)); + } else { + pipe_watcher_.ArmOrNotify(); + if (result == MOJO_RESULT_OK) { + DCHECK_GT(num_bytes, 0u); + bytes_read_ += num_bytes; + if (bytes_read_ == buffer_size) { + DCHECK(read_cb_); + bytes_read_ = 0; + std::move(read_cb_).Run(std::move(media_buffer_)); + } } } } @@ -186,18 +191,20 @@ MojoDecoderBufferWriter::MojoDecoderBufferWriter( mojo::ScopedDataPipeProducerHandle producer_handle) : producer_handle_(std::move(producer_handle)), - pipe_watcher_(FROM_HERE), + pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL), bytes_written_(0) { DVLOG(1) << __func__; MojoResult result = - pipe_watcher_.Start(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + pipe_watcher_.Watch(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, base::Bind(&MojoDecoderBufferWriter::OnPipeWritable, base::Unretained(this))); if (result != MOJO_RESULT_OK) { DVLOG(1) << __func__ << ": Failed to start watching the pipe. result=" << result; producer_handle_.reset(); + } else { + pipe_watcher_.ArmOrNotify(); } } @@ -273,12 +280,15 @@ if (IsPipeReadWriteError(result)) { OnPipeError(result); - } else if (result == MOJO_RESULT_OK) { - DCHECK_GT(num_bytes, 0u); - bytes_written_ += num_bytes; - if (bytes_written_ == buffer_size) { - media_buffer_ = nullptr; - bytes_written_ = 0; + } else { + pipe_watcher_.ArmOrNotify(); + if (result == MOJO_RESULT_OK) { + DCHECK_GT(num_bytes, 0u); + bytes_written_ += num_bytes; + if (bytes_written_ == buffer_size) { + media_buffer_ = nullptr; + bytes_written_ = 0; + } } }
diff --git a/media/mojo/common/mojo_decoder_buffer_converter.h b/media/mojo/common/mojo_decoder_buffer_converter.h index cc58469..10940f3 100644 --- a/media/mojo/common/mojo_decoder_buffer_converter.h +++ b/media/mojo/common/mojo_decoder_buffer_converter.h
@@ -12,7 +12,7 @@ #include "media/base/demuxer_stream.h" #include "media/mojo/interfaces/media_types.mojom.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace media { @@ -47,7 +47,7 @@ // For reading the data section of a DecoderBuffer. mojo::ScopedDataPipeConsumerHandle consumer_handle_; - mojo::Watcher pipe_watcher_; + mojo::SimpleWatcher pipe_watcher_; // Only valid during pending read. ReadCB read_cb_; @@ -85,7 +85,7 @@ // For writing the data section of DecoderBuffer into DataPipe. mojo::ScopedDataPipeProducerHandle producer_handle_; - mojo::Watcher pipe_watcher_; + mojo::SimpleWatcher pipe_watcher_; // Only valid when data is being written to the pipe. scoped_refptr<DecoderBuffer> media_buffer_;
diff --git a/media/remoting/demuxer_stream_adapter.cc b/media/remoting/demuxer_stream_adapter.cc index c12ee00..de8bfd0 100644 --- a/media/remoting/demuxer_stream_adapter.cc +++ b/media/remoting/demuxer_stream_adapter.cc
@@ -57,7 +57,7 @@ pending_flush_(false), current_pending_frame_offset_(0), pending_frame_is_eos_(false), - write_watcher_(FROM_HERE), + write_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL), media_status_(DemuxerStream::kOk), producer_handle_(std::move(producer_handle)), bytes_written_to_pipe_(0), @@ -202,9 +202,10 @@ // Starts Mojo watcher. if (!write_watcher_.IsWatching()) { DEMUXER_VLOG(2) << "Start Mojo data pipe watcher"; - write_watcher_.Start(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + write_watcher_.Watch(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, base::Bind(&DemuxerStreamAdapter::TryWriteData, weak_factory_.GetWeakPtr())); + write_watcher_.ArmOrNotify(); } } @@ -326,15 +327,17 @@ WriteDataRaw(producer_handle_.get(), pending_frame_.data() + current_pending_frame_offset_, &num_bytes, MOJO_WRITE_DATA_FLAG_NONE); - if (mojo_result != MOJO_RESULT_OK) { - if (mojo_result != MOJO_RESULT_SHOULD_WAIT) { - DEMUXER_VLOG(1) << "Pipe was closed unexpectedly (or a bug). result:" - << mojo_result; - OnFatalError(MOJO_PIPE_ERROR); - } + if (mojo_result != MOJO_RESULT_OK && mojo_result != MOJO_RESULT_SHOULD_WAIT) { + DEMUXER_VLOG(1) << "Pipe was closed unexpectedly (or a bug). result:" + << mojo_result; + OnFatalError(MOJO_PIPE_ERROR); return; } + write_watcher_.ArmOrNotify(); + if (mojo_result != MOJO_RESULT_OK) + return; + stream_sender_->ConsumeDataChunk(current_pending_frame_offset_, num_bytes, pending_frame_.size()); current_pending_frame_offset_ += num_bytes;
diff --git a/media/remoting/demuxer_stream_adapter.h b/media/remoting/demuxer_stream_adapter.h index 141fe8e..350ad665 100644 --- a/media/remoting/demuxer_stream_adapter.h +++ b/media/remoting/demuxer_stream_adapter.h
@@ -21,6 +21,7 @@ #include "media/remoting/rpc_broker.h" #include "media/remoting/triggers.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace base { class SingleThreadTaskRunner; @@ -167,7 +168,7 @@ bool pending_frame_is_eos_; // Monitor if data pipe is available to write data. - mojo::Watcher write_watcher_; + mojo::SimpleWatcher write_watcher_; // Keeps latest demuxer stream status and audio/video decoder config. DemuxerStream::Status media_status_;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java index 6a99fe15..e14adb1 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java
@@ -68,6 +68,17 @@ private static class WatcherResult implements Callback { private int mResult = Integer.MIN_VALUE; + private MessagePipeHandle mReadPipe; + + /** + * @param readPipe A MessagePipeHandle to read from when onResult triggers success. + */ + public WatcherResult(MessagePipeHandle readPipe) { + mReadPipe = readPipe; + } + public WatcherResult() { + this(null); + } /** * @see Callback#onResult(int) @@ -75,6 +86,11 @@ @Override public void onResult(int result) { this.mResult = result; + + if (result == MojoResult.OK && mReadPipe != null) { + mReadPipe.readMessage( + null, 0, MessagePipeHandle.ReadFlags.none().setMayDiscard(true)); + } } /** @@ -93,7 +109,7 @@ // Checking a correct result. Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); addHandlePairToClose(handles); - final WatcherResult watcherResult = new WatcherResult(); + final WatcherResult watcherResult = new WatcherResult(handles.first); assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult);
diff --git a/mojo/android/system/watcher_impl.cc b/mojo/android/system/watcher_impl.cc index 28d8c9f1..139dfb4 100644 --- a/mojo/android/system/watcher_impl.cc +++ b/mojo/android/system/watcher_impl.cc
@@ -15,7 +15,7 @@ #include "base/bind.h" #include "jni/WatcherImpl_jni.h" #include "mojo/public/cpp/system/handle.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace mojo { namespace android { @@ -26,7 +26,7 @@ class WatcherImpl { public: - WatcherImpl() : watcher_(FROM_HERE) {} + WatcherImpl() : watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC) {} ~WatcherImpl() = default; @@ -40,9 +40,8 @@ base::Bind(&WatcherImpl::OnHandleReady, base::Unretained(this)); MojoResult result = - watcher_.Start(mojo::Handle(static_cast<MojoHandle>(mojo_handle)), + watcher_.Watch(mojo::Handle(static_cast<MojoHandle>(mojo_handle)), static_cast<MojoHandleSignals>(signals), ready_callback); - if (result != MOJO_RESULT_OK) java_watcher_.Reset(); @@ -68,7 +67,7 @@ result); } - Watcher watcher_; + SimpleWatcher watcher_; base::android::ScopedJavaGlobalRef<jobject> java_watcher_; DISALLOW_COPY_AND_ASSIGN(WatcherImpl);
diff --git a/mojo/common/data_pipe_drainer.cc b/mojo/common/data_pipe_drainer.cc index 27bd893d..e705c8d 100644 --- a/mojo/common/data_pipe_drainer.cc +++ b/mojo/common/data_pipe_drainer.cc
@@ -17,10 +17,10 @@ mojo::ScopedDataPipeConsumerHandle source) : client_(client), source_(std::move(source)), - handle_watcher_(FROM_HERE), + handle_watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC), weak_factory_(this) { DCHECK(client_); - handle_watcher_.Start( + handle_watcher_.Watch( source_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&DataPipeDrainer::WaitComplete, weak_factory_.GetWeakPtr())); }
diff --git a/mojo/common/data_pipe_drainer.h b/mojo/common/data_pipe_drainer.h index d0366fa..5cff820 100644 --- a/mojo/common/data_pipe_drainer.h +++ b/mojo/common/data_pipe_drainer.h
@@ -11,7 +11,7 @@ #include "base/memory/weak_ptr.h" #include "mojo/common/mojo_common_export.h" #include "mojo/public/cpp/system/core.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace mojo { namespace common { @@ -36,7 +36,7 @@ Client* client_; mojo::ScopedDataPipeConsumerHandle source_; - mojo::Watcher handle_watcher_; + mojo::SimpleWatcher handle_watcher_; base::WeakPtrFactory<DataPipeDrainer> weak_factory_;
diff --git a/mojo/edk/embedder/entrypoints.cc b/mojo/edk/embedder/entrypoints.cc index f09c5e1..ecf1630 100644 --- a/mojo/edk/embedder/entrypoints.cc +++ b/mojo/edk/embedder/entrypoints.cc
@@ -45,15 +45,29 @@ signals_states); } -MojoResult MojoWatchImpl(MojoHandle handle, - MojoHandleSignals signals, - MojoWatchCallback callback, - uintptr_t context) { - return g_core->Watch(handle, signals, callback, context); +MojoResult MojoCreateWatcherImpl(MojoWatcherCallback callback, + MojoHandle* watcher_handle) { + return g_core->CreateWatcher(callback, watcher_handle); } -MojoResult MojoCancelWatchImpl(MojoHandle handle, uintptr_t context) { - return g_core->CancelWatch(handle, context); +MojoResult MojoArmWatcherImpl(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) { + return g_core->ArmWatcher(watcher_handle, num_ready_contexts, ready_contexts, + ready_results, ready_signals_states); +} + +MojoResult MojoWatchImpl(MojoHandle watcher_handle, + MojoHandle handle, + MojoHandleSignals signals, + uintptr_t context) { + return g_core->Watch(watcher_handle, handle, signals, context); +} + +MojoResult MojoCancelWatchImpl(MojoHandle watcher_handle, uintptr_t context) { + return g_core->CancelWatch(watcher_handle, context); } MojoResult MojoAllocMessageImpl(uint32_t num_bytes, @@ -287,8 +301,10 @@ MojoAddHandleImpl, MojoRemoveHandleImpl, MojoGetReadyHandlesImpl, + MojoCreateWatcherImpl, MojoWatchImpl, MojoCancelWatchImpl, + MojoArmWatcherImpl, MojoFuseMessagePipesImpl, MojoWriteMessageNewImpl, MojoReadMessageNewImpl,
diff --git a/mojo/edk/js/drain_data.cc b/mojo/edk/js/drain_data.cc index cfd0bb5..334ced32 100644 --- a/mojo/edk/js/drain_data.cc +++ b/mojo/edk/js/drain_data.cc
@@ -23,7 +23,7 @@ DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle) : isolate_(isolate), handle_(DataPipeConsumerHandle(handle.value())), - handle_watcher_(FROM_HERE) { + handle_watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC) { v8::Handle<v8::Context> context(isolate_->GetCurrentContext()); runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr(); @@ -43,7 +43,7 @@ } void DrainData::WaitForData() { - handle_watcher_.Start( + handle_watcher_.Watch( handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&DrainData::DataReady, base::Unretained(this))); }
diff --git a/mojo/edk/js/drain_data.h b/mojo/edk/js/drain_data.h index 6e8555c..42da90f 100644 --- a/mojo/edk/js/drain_data.h +++ b/mojo/edk/js/drain_data.h
@@ -10,7 +10,7 @@ #include "gin/runner.h" #include "mojo/public/cpp/system/core.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "v8/include/v8.h" namespace mojo { @@ -52,7 +52,7 @@ v8::Isolate* isolate_; ScopedDataPipeConsumerHandle handle_; - Watcher handle_watcher_; + SimpleWatcher handle_watcher_; base::WeakPtr<gin::Runner> runner_; v8::UniquePersistent<v8::Promise::Resolver> resolver_; std::vector<std::unique_ptr<DataBuffer>> data_buffers_;
diff --git a/mojo/edk/js/waiting_callback.cc b/mojo/edk/js/waiting_callback.cc index fada039..6ad4bd0 100644 --- a/mojo/edk/js/waiting_callback.cc +++ b/mojo/edk/js/waiting_callback.cc
@@ -32,7 +32,7 @@ bool one_shot) { gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle( isolate, new WaitingCallback(isolate, callback, one_shot)); - MojoResult result = waiting_callback->watcher_.Start( + MojoResult result = waiting_callback->watcher_.Watch( handle_wrapper->get(), signals, base::Bind(&WaitingCallback::OnHandleReady, base::Unretained(waiting_callback.get()))); @@ -53,7 +53,7 @@ v8::Handle<v8::Function> callback, bool one_shot) : one_shot_(one_shot), - watcher_(FROM_HERE), + watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC), weak_factory_(this) { v8::Handle<v8::Context> context = isolate->GetCurrentContext(); runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
diff --git a/mojo/edk/js/waiting_callback.h b/mojo/edk/js/waiting_callback.h index 1195a98..f97b389a 100644 --- a/mojo/edk/js/waiting_callback.h +++ b/mojo/edk/js/waiting_callback.h
@@ -12,7 +12,7 @@ #include "gin/wrappable.h" #include "mojo/edk/js/handle.h" #include "mojo/public/cpp/system/core.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace mojo { namespace edk { @@ -54,7 +54,7 @@ const bool one_shot_; base::WeakPtr<gin::Runner> runner_; - Watcher watcher_; + SimpleWatcher watcher_; base::WeakPtrFactory<WaitingCallback> weak_factory_; DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index b0acf237..3c94e153 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn
@@ -66,8 +66,10 @@ "wait_set_dispatcher.h", "waiter.cc", "waiter.h", - "watcher.cc", - "watcher.h", + "watch.cc", + "watch.h", + "watcher_dispatcher.cc", + "watcher_dispatcher.h", "watcher_set.cc", "watcher_set.h", ] @@ -167,7 +169,7 @@ "waiter_test_utils.cc", "waiter_test_utils.h", "waiter_unittest.cc", - "watch_unittest.cc", + "watcher_unittest.cc", ] if (!is_ios) {
diff --git a/mojo/edk/system/awakable_list.cc b/mojo/edk/system/awakable_list.cc index 2045f32..429e691 100644 --- a/mojo/edk/system/awakable_list.cc +++ b/mojo/edk/system/awakable_list.cc
@@ -39,7 +39,6 @@ } } awakables_.erase(last, awakables_.end()); - watchers_.NotifyForStateChange(state); } void AwakableList::CancelAll() { @@ -48,7 +47,6 @@ it->awakable->Awake(MOJO_RESULT_CANCELLED, it->context); } awakables_.clear(); - watchers_.NotifyClosed(); } void AwakableList::Add(Awakable* awakable, @@ -72,16 +70,5 @@ awakables_.erase(last, awakables_.end()); } -MojoResult AwakableList::AddWatcher(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context, - const HandleSignalsState& current_state) { - return watchers_.Add(signals, callback, context, current_state); -} - -MojoResult AwakableList::RemoveWatcher(uintptr_t context) { - return watchers_.Remove(context); -} - } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/awakable_list.h b/mojo/edk/system/awakable_list.h index 355677f..34d6b06 100644 --- a/mojo/edk/system/awakable_list.h +++ b/mojo/edk/system/awakable_list.h
@@ -12,8 +12,6 @@ #include "base/macros.h" #include "mojo/edk/system/system_impl_export.h" -#include "mojo/edk/system/watcher.h" -#include "mojo/edk/system/watcher_set.h" #include "mojo/public/c/system/types.h" namespace mojo { @@ -39,13 +37,6 @@ void Add(Awakable* awakable, MojoHandleSignals signals, uintptr_t context); void Remove(Awakable* awakable); - // Add and remove Watchers to this AwakableList. - MojoResult AddWatcher(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context, - const HandleSignalsState& current_state); - MojoResult RemoveWatcher(uintptr_t context); - private: struct AwakeInfo { AwakeInfo(Awakable* awakable, MojoHandleSignals signals, uintptr_t context) @@ -59,10 +50,6 @@ AwakeInfoList awakables_; - // TODO: Remove AwakableList and instead use WatcherSet directly in - // dispatchers. - WatcherSet watchers_; - DISALLOW_COPY_AND_ASSIGN(AwakableList); };
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc index 1e0bf4e..cfe01fa 100644 --- a/mojo/edk/system/core.cc +++ b/mojo/edk/system/core.cc
@@ -35,6 +35,7 @@ #include "mojo/edk/system/shared_buffer_dispatcher.h" #include "mojo/edk/system/wait_set_dispatcher.h" #include "mojo/edk/system/waiter.h" +#include "mojo/edk/system/watcher_dispatcher.h" namespace mojo { namespace edk { @@ -48,15 +49,6 @@ // pipes too; for now we just use a constant. This only affects bootstrap pipes. const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL; -void CallWatchCallback(MojoWatchCallback callback, - uintptr_t context, - MojoResult result, - const HandleSignalsState& signals_state, - MojoWatchNotificationFlags flags) { - callback(context, result, static_cast<MojoHandleSignalsState>(signals_state), - flags); -} - MojoResult MojoPlatformHandleToScopedPlatformHandle( const MojoPlatformHandle* platform_handle, ScopedPlatformHandle* out_handle) { @@ -428,24 +420,50 @@ return rv; } -MojoResult Core::Watch(MojoHandle handle, - MojoHandleSignals signals, - MojoWatchCallback callback, - uintptr_t context) { +MojoResult Core::CreateWatcher(MojoWatcherCallback callback, + MojoHandle* watcher_handle) { RequestContext request_context; - scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); - if (!dispatcher) + if (!watcher_handle) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->Watch( - signals, base::Bind(&CallWatchCallback, callback, context), context); + *watcher_handle = AddDispatcher(new WatcherDispatcher(callback)); + if (*watcher_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + return MOJO_RESULT_OK; } -MojoResult Core::CancelWatch(MojoHandle handle, uintptr_t context) { +MojoResult Core::Watch(MojoHandle watcher_handle, + MojoHandle handle, + MojoHandleSignals signals, + uintptr_t context) { RequestContext request_context; + scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle); + if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) + return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->CancelWatch(context); + return watcher->WatchDispatcher(dispatcher, signals, context); +} + +MojoResult Core::CancelWatch(MojoHandle watcher_handle, uintptr_t context) { + RequestContext request_context; + scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle); + if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) + return MOJO_RESULT_INVALID_ARGUMENT; + return watcher->CancelWatch(context); +} + +MojoResult Core::ArmWatcher(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) { + RequestContext request_context; + scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle); + if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) + return MOJO_RESULT_INVALID_ARGUMENT; + return watcher->Arm(num_ready_contexts, ready_contexts, ready_results, + ready_signals_states); } MojoResult Core::AllocMessage(uint32_t num_bytes,
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h index 1e20a87..2ef9b7f 100644 --- a/mojo/edk/system/core.h +++ b/mojo/edk/system/core.h
@@ -27,6 +27,7 @@ #include "mojo/public/c/system/message_pipe.h" #include "mojo/public/c/system/platform_handle.h" #include "mojo/public/c/system/types.h" +#include "mojo/public/c/system/watcher.h" #include "mojo/public/cpp/system/message_pipe.h" namespace base { @@ -145,11 +146,18 @@ MojoDeadline deadline, uint32_t* result_index, MojoHandleSignalsState* signals_states); - MojoResult Watch(MojoHandle handle, + MojoResult CreateWatcher(MojoWatcherCallback callback, + MojoHandle* watcher_handle); + MojoResult Watch(MojoHandle watcher_handle, + MojoHandle handle, MojoHandleSignals signals, - MojoWatchCallback callback, uintptr_t context); - MojoResult CancelWatch(MojoHandle handle, uintptr_t context); + MojoResult CancelWatch(MojoHandle watcher_handle, uintptr_t context); + MojoResult ArmWatcher(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states); MojoResult AllocMessage(uint32_t num_bytes, const MojoHandle* handles, uint32_t num_handles,
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc index c908e3a..474e99d 100644 --- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
@@ -80,6 +80,7 @@ node_controller_(node_controller), control_port_(control_port), pipe_id_(pipe_id), + watchers_(this), shared_ring_buffer_(shared_ring_buffer) { if (initialized) { base::AutoLock lock(lock_); @@ -97,34 +98,10 @@ return CloseNoLock(); } - -MojoResult DataPipeConsumerDispatcher::Watch( - MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) { - base::AutoLock lock(lock_); - - if (is_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakable_list_.AddWatcher( - signals, callback, context, GetHandleSignalsStateNoLock()); -} - -MojoResult DataPipeConsumerDispatcher::CancelWatch(uintptr_t context) { - base::AutoLock lock(lock_); - - if (is_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakable_list_.RemoveWatcher(context); -} - MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, uint32_t* num_bytes, MojoReadDataFlags flags) { base::AutoLock lock(lock_); - new_data_available_ = false; if (!shared_ring_buffer_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; @@ -132,6 +109,9 @@ if (in_two_phase_read_) return MOJO_RESULT_BUSY; + const bool had_new_data = new_data_available_; + new_data_available_ = false; + if ((flags & MOJO_READ_DATA_FLAG_QUERY)) { if ((flags & MOJO_READ_DATA_FLAG_PEEK) || (flags & MOJO_READ_DATA_FLAG_DISCARD)) @@ -140,6 +120,9 @@ DVLOG_IF(2, elements) << "Query mode: ignoring non-null |elements|"; *num_bytes = static_cast<uint32_t>(bytes_available_); + + if (had_new_data) + watchers_.NotifyState(GetHandleSignalsStateNoLock()); return MOJO_RESULT_OK; } @@ -162,12 +145,16 @@ all_or_none ? max_num_bytes_to_read : 0; if (min_num_bytes_to_read > bytes_available_) { + if (had_new_data) + watchers_.NotifyState(GetHandleSignalsStateNoLock()); return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION : MOJO_RESULT_OUT_OF_RANGE; } uint32_t bytes_to_read = std::min(max_num_bytes_to_read, bytes_available_); if (bytes_to_read == 0) { + if (had_new_data) + watchers_.NotifyState(GetHandleSignalsStateNoLock()); return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION : MOJO_RESULT_SHOULD_WAIT; } @@ -199,6 +186,10 @@ NotifyRead(bytes_to_read); } + // We may have just read the last available data and thus changed the signals + // state. + watchers_.NotifyState(GetHandleSignalsStateNoLock()); + return MOJO_RESULT_OK; } @@ -206,7 +197,6 @@ uint32_t* buffer_num_bytes, MojoReadDataFlags flags) { base::AutoLock lock(lock_); - new_data_available_ = false; if (!shared_ring_buffer_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; @@ -219,7 +209,12 @@ (flags & MOJO_READ_DATA_FLAG_PEEK)) return MOJO_RESULT_INVALID_ARGUMENT; + const bool had_new_data = new_data_available_; + new_data_available_ = false; + if (bytes_available_ == 0) { + if (had_new_data) + watchers_.NotifyState(GetHandleSignalsStateNoLock()); return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION : MOJO_RESULT_SHOULD_WAIT; } @@ -237,6 +232,9 @@ *buffer_num_bytes = bytes_to_read; two_phase_max_bytes_read_ = bytes_to_read; + if (had_new_data) + watchers_.NotifyState(GetHandleSignalsStateNoLock()); + return MOJO_RESULT_OK; } @@ -273,6 +271,7 @@ HandleSignalsState new_state = GetHandleSignalsStateNoLock(); if (!new_state.equals(old_state)) awakable_list_.AwakeForStateChange(new_state); + watchers_.NotifyState(new_state); return rv; } @@ -282,6 +281,24 @@ return GetHandleSignalsStateNoLock(); } +MojoResult DataPipeConsumerDispatcher::AddWatcherRef( + const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) { + base::AutoLock lock(lock_); + if (is_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock()); +} + +MojoResult DataPipeConsumerDispatcher::RemoveWatcherRef( + WatcherDispatcher* watcher, + uintptr_t context) { + base::AutoLock lock(lock_); + if (is_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Remove(watcher, context); +} + MojoResult DataPipeConsumerDispatcher::AddAwakable( Awakable* awakable, MojoHandleSignals signals, @@ -464,6 +481,7 @@ shared_ring_buffer_ = nullptr; awakable_list_.CancelAll(); + watchers_.NotifyClosed(); if (!transferred_) { base::AutoUnlock unlock(lock_); node_controller_->ClosePort(control_port_); @@ -581,7 +599,9 @@ new_data_available_ = true; if (peer_closed_ != was_peer_closed || has_new_data) { - awakable_list_.AwakeForStateChange(GetHandleSignalsStateNoLock()); + HandleSignalsState state = GetHandleSignalsStateNoLock(); + awakable_list_.AwakeForStateChange(state); + watchers_.NotifyState(state); } }
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.h b/mojo/edk/system/data_pipe_consumer_dispatcher.h index b323c16..26ceadf 100644 --- a/mojo/edk/system/data_pipe_consumer_dispatcher.h +++ b/mojo/edk/system/data_pipe_consumer_dispatcher.h
@@ -20,6 +20,7 @@ #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/ports/port_ref.h" #include "mojo/edk/system/system_impl_export.h" +#include "mojo/edk/system/watcher_set.h" namespace mojo { namespace edk { @@ -43,10 +44,6 @@ // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) override; - MojoResult CancelWatch(uintptr_t context) override; MojoResult ReadData(void* elements, uint32_t* num_bytes, MojoReadDataFlags flags) override; @@ -55,6 +52,10 @@ MojoReadDataFlags flags) override; MojoResult EndReadData(uint32_t num_bytes_read) override; HandleSignalsState GetHandleSignalsState() const override; + MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) override; + MojoResult RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context) override; MojoResult AddAwakable(Awakable* awakable, MojoHandleSignals signals, uintptr_t context, @@ -101,6 +102,7 @@ mutable base::Lock lock_; AwakableList awakable_list_; + WatcherSet watchers_; scoped_refptr<PlatformSharedBuffer> shared_ring_buffer_; std::unique_ptr<PlatformSharedBufferMapping> ring_buffer_mapping_;
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc index 8c1993aa..71c61963e 100644 --- a/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_producer_dispatcher.cc
@@ -79,6 +79,7 @@ node_controller_(node_controller), control_port_(control_port), pipe_id_(pipe_id), + watchers_(this), shared_ring_buffer_(shared_ring_buffer), available_capacity_(options_.capacity_num_bytes) { if (initialized) { @@ -97,28 +98,6 @@ return CloseNoLock(); } -MojoResult DataPipeProducerDispatcher::Watch( - MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) { - base::AutoLock lock(lock_); - - if (is_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakable_list_.AddWatcher( - signals, callback, context, GetHandleSignalsStateNoLock()); -} - -MojoResult DataPipeProducerDispatcher::CancelWatch(uintptr_t context) { - base::AutoLock lock(lock_); - - if (is_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakable_list_.RemoveWatcher(context); -} - MojoResult DataPipeProducerDispatcher::WriteData(const void* elements, uint32_t* num_bytes, MojoWriteDataFlags flags) { @@ -179,6 +158,7 @@ HandleSignalsState new_state = GetHandleSignalsStateNoLock(); if (!new_state.equals(old_state)) awakable_list_.AwakeForStateChange(new_state); + watchers_.NotifyState(new_state); base::AutoUnlock unlock(lock_); NotifyWrite(num_bytes_to_write); @@ -193,6 +173,11 @@ base::AutoLock lock(lock_); if (!shared_ring_buffer_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; + + // These flags may not be used in two-phase mode. + if (flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) + return MOJO_RESULT_INVALID_ARGUMENT; + if (in_two_phase_write_) return MOJO_RESULT_BUSY; if (peer_closed_) @@ -251,6 +236,7 @@ HandleSignalsState new_state = GetHandleSignalsStateNoLock(); if (new_state.satisfies(MOJO_HANDLE_SIGNAL_WRITABLE)) awakable_list_.AwakeForStateChange(new_state); + watchers_.NotifyState(new_state); return rv; } @@ -260,6 +246,24 @@ return GetHandleSignalsStateNoLock(); } +MojoResult DataPipeProducerDispatcher::AddWatcherRef( + const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) { + base::AutoLock lock(lock_); + if (is_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock()); +} + +MojoResult DataPipeProducerDispatcher::RemoveWatcherRef( + WatcherDispatcher* watcher, + uintptr_t context) { + base::AutoLock lock(lock_); + if (is_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Remove(watcher, context); +} + MojoResult DataPipeProducerDispatcher::AddAwakable( Awakable* awakable, MojoHandleSignals signals, @@ -356,7 +360,10 @@ DCHECK(in_transit_); in_transit_ = false; buffer_handle_for_transit_.reset(); - awakable_list_.AwakeForStateChange(GetHandleSignalsStateNoLock()); + + HandleSignalsState state = GetHandleSignalsStateNoLock(); + awakable_list_.AwakeForStateChange(state); + watchers_.NotifyState(state); } // static @@ -440,6 +447,7 @@ shared_ring_buffer_ = nullptr; awakable_list_.CancelAll(); + watchers_.NotifyClosed(); if (!transferred_) { base::AutoUnlock unlock(lock_); node_controller_->ClosePort(control_port_); @@ -453,8 +461,7 @@ lock_.AssertAcquired(); HandleSignalsState rv; if (!peer_closed_) { - if (!in_two_phase_write_ && shared_ring_buffer_ && - available_capacity_ > 0) + if (!in_two_phase_write_ && shared_ring_buffer_ && available_capacity_ > 0) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; } else { @@ -541,7 +548,9 @@ if (peer_closed_ != was_peer_closed || available_capacity_ != previous_capacity) { - awakable_list_.AwakeForStateChange(GetHandleSignalsStateNoLock()); + HandleSignalsState state = GetHandleSignalsStateNoLock(); + awakable_list_.AwakeForStateChange(state); + watchers_.NotifyState(state); } }
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.h b/mojo/edk/system/data_pipe_producer_dispatcher.h index a55234a..e472994 100644 --- a/mojo/edk/system/data_pipe_producer_dispatcher.h +++ b/mojo/edk/system/data_pipe_producer_dispatcher.h
@@ -19,6 +19,7 @@ #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/ports/port_ref.h" #include "mojo/edk/system/system_impl_export.h" +#include "mojo/edk/system/watcher_set.h" namespace mojo { namespace edk { @@ -43,10 +44,6 @@ // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) override; - MojoResult CancelWatch(uintptr_t context) override; MojoResult WriteData(const void* elements, uint32_t* num_bytes, MojoReadDataFlags flags) override; @@ -55,6 +52,10 @@ MojoWriteDataFlags flags) override; MojoResult EndWriteData(uint32_t num_bytes_written) override; HandleSignalsState GetHandleSignalsState() const override; + MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) override; + MojoResult RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context) override; MojoResult AddAwakable(Awakable* awakable, MojoHandleSignals signals, uintptr_t context, @@ -104,6 +105,7 @@ mutable base::Lock lock_; AwakableList awakable_list_; + WatcherSet watchers_; bool buffer_requested_ = false;
diff --git a/mojo/edk/system/data_pipe_unittest.cc b/mojo/edk/system/data_pipe_unittest.cc index 610aeac..11474962 100644 --- a/mojo/edk/system/data_pipe_unittest.cc +++ b/mojo/edk/system/data_pipe_unittest.cc
@@ -21,7 +21,7 @@ #include "mojo/public/c/system/data_pipe.h" #include "mojo/public/c/system/functions.h" #include "mojo/public/c/system/message_pipe.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { @@ -2029,7 +2029,7 @@ base::MessageLoop message_loop; - // Wait on producer 1 and consumer 1 using Watchers. + // Wait on producer 1 and consumer 1 using SimpleWatchers. { base::RunLoop run_loop; int count = 0; @@ -2040,12 +2040,16 @@ loop->Quit(); }, &run_loop, &count); - Watcher producer_watcher(FROM_HERE), consumer_watcher(FROM_HERE); - producer_watcher.Start( - Handle(producers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, callback); - consumer_watcher.Start( - Handle(consumers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, callback); + SimpleWatcher producer_watcher(FROM_HERE, + SimpleWatcher::ArmingPolicy::AUTOMATIC); + SimpleWatcher consumer_watcher(FROM_HERE, + SimpleWatcher::ArmingPolicy::AUTOMATIC); + producer_watcher.Watch(Handle(producers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + callback); + consumer_watcher.Watch(Handle(consumers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + callback); run_loop.Run(); + EXPECT_EQ(2, count); } // Wait on producer 2 by polling with MojoWriteData.
diff --git a/mojo/edk/system/dispatcher.cc b/mojo/edk/system/dispatcher.cc index 7d701b2..97e87e068 100644 --- a/mojo/edk/system/dispatcher.cc +++ b/mojo/edk/system/dispatcher.cc
@@ -22,9 +22,9 @@ Dispatcher::DispatcherInTransit::~DispatcherInTransit() {} -MojoResult Dispatcher::Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) { +MojoResult Dispatcher::WatchDispatcher(scoped_refptr<Dispatcher> dispatcher, + MojoHandleSignals signals, + uintptr_t context) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -32,6 +32,13 @@ return MOJO_RESULT_INVALID_ARGUMENT; } +MojoResult Dispatcher::Arm(uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) { + return MOJO_RESULT_INVALID_ARGUMENT; +} + MojoResult Dispatcher::WriteMessage(std::unique_ptr<MessageForTransit> message, MojoWriteMessageFlags flags) { return MOJO_RESULT_INVALID_ARGUMENT; @@ -115,6 +122,17 @@ return HandleSignalsState(); } +MojoResult Dispatcher::AddWatcherRef( + const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) { + return MOJO_RESULT_INVALID_ARGUMENT; +} + +MojoResult Dispatcher::RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context) { + return MOJO_RESULT_INVALID_ARGUMENT; +} + MojoResult Dispatcher::AddAwakable(Awakable* awakable, MojoHandleSignals signals, uintptr_t context,
diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h index 9dca67f..88a9de7 100644 --- a/mojo/edk/system/dispatcher.h +++ b/mojo/edk/system/dispatcher.h
@@ -20,7 +20,7 @@ #include "mojo/edk/system/handle_signals_state.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/system_impl_export.h" -#include "mojo/edk/system/watcher.h" +#include "mojo/edk/system/watch.h" #include "mojo/public/c/system/buffer.h" #include "mojo/public/c/system/data_pipe.h" #include "mojo/public/c/system/message_pipe.h" @@ -57,6 +57,7 @@ DATA_PIPE_CONSUMER, SHARED_BUFFER, WAIT_SET, + WATCHER, // "Private" types (not exposed via the public interface): PLATFORM_HANDLE = -1, @@ -67,13 +68,16 @@ virtual Type GetType() const = 0; virtual MojoResult Close() = 0; - ///////////// Watch API //////////////////// + ///////////// Watcher API //////////////////// - virtual MojoResult Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context); - + virtual MojoResult WatchDispatcher(scoped_refptr<Dispatcher> dispatcher, + MojoHandleSignals signals, + uintptr_t context); virtual MojoResult CancelWatch(uintptr_t context); + virtual MojoResult Arm(uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states); ///////////// Message pipe API ///////////// @@ -158,6 +162,18 @@ // threads. virtual HandleSignalsState GetHandleSignalsState() const; + // Adds a WatcherDispatcher reference to this dispatcher, to be notified of + // all subsequent changes to handle state including signal changes or closure. + // The reference is associated with a |context| for disambiguation of + // removals. + virtual MojoResult AddWatcherRef( + const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context); + + // Removes a WatcherDispatcher reference from this dispatcher. + virtual MojoResult RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context); + // Adds an awakable to this dispatcher, which will be woken up when this // object changes state to satisfy |signals| with context |context|. It will // also be woken up when it becomes impossible for the object to ever satisfy
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc index f27336b..76f4123 100644 --- a/mojo/edk/system/message_pipe_dispatcher.cc +++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -164,7 +164,8 @@ : node_controller_(node_controller), port_(port), pipe_id_(pipe_id), - endpoint_(endpoint) { + endpoint_(endpoint), + watchers_(this) { DVLOG(2) << "Creating new MessagePipeDispatcher for port " << port.name() << " [pipe_id=" << pipe_id << "; endpoint=" << endpoint << "]"; @@ -183,6 +184,7 @@ port0 = port_; port_closed_.Set(true); awakables_.CancelAll(); + watchers_.NotifyClosed(); } ports::PortRef port1; @@ -191,6 +193,7 @@ port1 = other->port_; other->port_closed_.Set(true); other->awakables_.CancelAll(); + other->watchers_.NotifyClosed(); } // Both ports are always closed by this call. @@ -209,27 +212,6 @@ return CloseNoLock(); } -MojoResult MessagePipeDispatcher::Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) { - base::AutoLock lock(signal_lock_); - - if (port_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakables_.AddWatcher( - signals, callback, context, GetHandleSignalsStateNoLock()); -} - -MojoResult MessagePipeDispatcher::CancelWatch(uintptr_t context) { - base::AutoLock lock(signal_lock_); - - if (port_closed_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - return awakables_.RemoveWatcher(context); -} - MojoResult MessagePipeDispatcher::WriteMessage( std::unique_ptr<MessageForTransit> message, MojoWriteMessageFlags flags) { @@ -299,6 +281,12 @@ } if (no_space) { + if (may_discard) { + // May have been the last message on the pipe. Need to update signals just + // in case. + base::AutoLock lock(signal_lock_); + watchers_.NotifyState(GetHandleSignalsStateNoLock()); + } // |*num_handles| (and/or |*num_bytes| if |read_any_size| is false) wasn't // sufficient to hold this message's data. The message will still be in // queue unless MOJO_READ_MESSAGE_FLAG_MAY_DISCARD was set. @@ -319,6 +307,13 @@ // Alright! We have a message and the caller has provided sufficient storage // in which to receive it. + { + // We need to update anyone watching our signals in case that was the last + // available message. + base::AutoLock lock(signal_lock_); + watchers_.NotifyState(GetHandleSignalsStateNoLock()); + } + std::unique_ptr<PortsMessage> msg( static_cast<PortsMessage*>(ports_message.release())); @@ -396,6 +391,23 @@ return GetHandleSignalsStateNoLock(); } +MojoResult MessagePipeDispatcher::AddWatcherRef( + const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) { + base::AutoLock lock(signal_lock_); + if (port_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock()); +} + +MojoResult MessagePipeDispatcher::RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context) { + base::AutoLock lock(signal_lock_); + if (port_closed_ || in_transit_) + return MOJO_RESULT_INVALID_ARGUMENT; + return watchers_.Remove(watcher, context); +} + MojoResult MessagePipeDispatcher::AddAwakable( Awakable* awakable, MojoHandleSignals signals, @@ -496,7 +508,9 @@ in_transit_.Set(false); // Something may have happened while we were waiting for potential transit. - awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock()); + HandleSignalsState state = GetHandleSignalsStateNoLock(); + awakables_.AwakeForStateChange(state); + watchers_.NotifyState(state); } // static @@ -532,6 +546,7 @@ port_closed_.Set(true); awakables_.CancelAll(); + watchers_.NotifyClosed(); if (!port_transferred_) { base::AutoUnlock unlock(signal_lock_); @@ -596,7 +611,9 @@ } #endif - awakables_.AwakeForStateChange(GetHandleSignalsStateNoLock()); + HandleSignalsState state = GetHandleSignalsStateNoLock(); + awakables_.AwakeForStateChange(state); + watchers_.NotifyState(state); } } // namespace edk
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h index 6743222b..a7c1e69 100644 --- a/mojo/edk/system/message_pipe_dispatcher.h +++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -16,6 +16,7 @@ #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/message_for_transit.h" #include "mojo/edk/system/ports/port_ref.h" +#include "mojo/edk/system/watcher_set.h" namespace mojo { namespace edk { @@ -48,10 +49,6 @@ // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult Watch(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, - uintptr_t context) override; - MojoResult CancelWatch(uintptr_t context) override; MojoResult WriteMessage(std::unique_ptr<MessageForTransit> message, MojoWriteMessageFlags flags) override; MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message, @@ -61,6 +58,10 @@ MojoReadMessageFlags flags, bool read_any_size) override; HandleSignalsState GetHandleSignalsState() const override; + MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher, + uintptr_t context) override; + MojoResult RemoveWatcherRef(WatcherDispatcher* watcher, + uintptr_t context) override; MojoResult AddAwakable(Awakable* awakable, MojoHandleSignals signals, uintptr_t context, @@ -111,6 +112,7 @@ bool port_transferred_ = false; AtomicFlag port_closed_; AwakableList awakables_; + WatcherSet watchers_; DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher); };
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index 498980c..f8e29d63 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -31,7 +31,7 @@ #include "mojo/public/c/system/buffer.h" #include "mojo/public/c/system/functions.h" #include "mojo/public/c/system/types.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" #include "testing/gtest/include/gtest/gtest.h" @@ -1271,15 +1271,17 @@ base::MessageLoop message_loop; - // Wait on handle 1 using a Watcher. + // Wait on handle 1 using a SimpleWatcher. { base::RunLoop run_loop; - Watcher watcher(FROM_HERE); - watcher.Start(Handle(handles[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, - base::Bind([] (base::RunLoop* loop, MojoResult result) { - EXPECT_EQ(MOJO_RESULT_OK, result); - loop->Quit(); - }, &run_loop)); + SimpleWatcher watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + watcher.Watch(Handle(handles[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + base::Bind( + [](base::RunLoop* loop, MojoResult result) { + EXPECT_EQ(MOJO_RESULT_OK, result); + loop->Quit(); + }, + &run_loop)); run_loop.Run(); }
diff --git a/mojo/edk/system/request_context.cc b/mojo/edk/system/request_context.cc index 6370ab1..5de65d7 100644 --- a/mojo/edk/system/request_context.cc +++ b/mojo/edk/system/request_context.cc
@@ -36,27 +36,34 @@ // since we're starting over at the bottom of the stack. tls_context_->Set(nullptr); - MojoWatchNotificationFlags flags = MOJO_WATCH_NOTIFICATION_FLAG_NONE; + MojoWatcherNotificationFlags flags = MOJO_WATCHER_NOTIFICATION_FLAG_NONE; if (source_ == Source::SYSTEM) - flags |= MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM; + flags |= MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM; - // We run all cancellation finalizers first. This is necessary because it's - // possible that one of the cancelled watchers has other pending finalizers + // We send all cancellation notifications first. This is necessary because + // it's possible that cancelled watches have other pending notifications // attached to this RequestContext. // - // From the application's perspective the watch has already been cancelled, - // so we have to honor our contract which guarantees no more notifications. - for (const scoped_refptr<Watcher>& watcher : - watch_cancel_finalizers_.container()) - watcher->Cancel(); + // From the application's perspective the watch is cancelled as soon as this + // notification is received, and dispatching the cancellation notification + // updates some internal Watch state to ensure no further notifications + // fire. Because notifications on a single Watch are mutually exclusive, + // this is sufficient to guarantee that MOJO_RESULT_CANCELLED is the last + // notification received; which is the guarantee the API makes. + for (const scoped_refptr<Watch>& watch : + watch_cancel_finalizers_.container()) { + static const HandleSignalsState closed_state = {0, 0}; + + // Establish a new RequestContext to capture and run any new notifications + // triggered by the callback invocation. + RequestContext inner_context(source_); + watch->InvokeCallback(MOJO_RESULT_CANCELLED, closed_state, flags); + } for (const WatchNotifyFinalizer& watch : - watch_notify_finalizers_.container()) { - // Establish a new request context for the extent of each callback to - // ensure that they don't themselves invoke callbacks while holding a - // watcher lock. - RequestContext request_context(source_); - watch.watcher->MaybeInvokeCallback(watch.result, watch.state, flags); + watch_notify_finalizers_.container()) { + RequestContext inner_context(source_); + watch.watch->InvokeCallback(watch.result, watch.state, flags); } } else { // It should be impossible for nested contexts to have finalizers. @@ -71,18 +78,17 @@ return g_current_context.Pointer()->Get(); } -void RequestContext::AddWatchNotifyFinalizer( - scoped_refptr<Watcher> watcher, - MojoResult result, - const HandleSignalsState& state) { +void RequestContext::AddWatchNotifyFinalizer(scoped_refptr<Watch> watch, + MojoResult result, + const HandleSignalsState& state) { DCHECK(IsCurrent()); watch_notify_finalizers_->push_back( - WatchNotifyFinalizer(std::move(watcher), result, state)); + WatchNotifyFinalizer(std::move(watch), result, state)); } -void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watcher> watcher) { +void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watch> watch) { DCHECK(IsCurrent()); - watch_cancel_finalizers_->push_back(std::move(watcher)); + watch_cancel_finalizers_->push_back(std::move(watch)); } bool RequestContext::IsCurrent() const { @@ -90,10 +96,10 @@ } RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer( - scoped_refptr<Watcher> watcher, + scoped_refptr<Watch> watch, MojoResult result, const HandleSignalsState& state) - : watcher(std::move(watcher)), result(result), state(state) {} + : watch(std::move(watch)), result(result), state(state) {} RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer( const WatchNotifyFinalizer& other) = default;
diff --git a/mojo/edk/system/request_context.h b/mojo/edk/system/request_context.h index 7aa0e69..d1f43bd 100644 --- a/mojo/edk/system/request_context.h +++ b/mojo/edk/system/request_context.h
@@ -9,7 +9,7 @@ #include "base/macros.h" #include "mojo/edk/system/handle_signals_state.h" #include "mojo/edk/system/system_impl_export.h" -#include "mojo/edk/system/watcher.h" +#include "mojo/edk/system/watch.h" namespace base { template<typename T> class ThreadLocalPointer; @@ -49,43 +49,44 @@ // Adds a finalizer to this RequestContext corresponding to a watch callback // which should be triggered in response to some handle state change. If - // the Watcher hasn't been cancelled by the time this RequestContext is + // the WatcherDispatcher hasn't been closed by the time this RequestContext is // destroyed, its WatchCallback will be invoked with |result| and |state| // arguments. - void AddWatchNotifyFinalizer(scoped_refptr<Watcher> watcher, + void AddWatchNotifyFinalizer(scoped_refptr<Watch> watch, MojoResult result, const HandleSignalsState& state); - // Adds a finalizer to this RequestContext which cancels a watch. - void AddWatchCancelFinalizer(scoped_refptr<Watcher> watcher); + // Adds a finalizer to this RequestContext corresponding to a watch callback + // which should be triggered to notify of watch cancellation. This appends to + // a separate finalizer list from AddWatchNotifyFinalizer, as pending + // cancellations must always preempt other pending notifications. + void AddWatchCancelFinalizer(scoped_refptr<Watch> watch); private: // Is this request context the current one? bool IsCurrent() const; struct WatchNotifyFinalizer { - WatchNotifyFinalizer(scoped_refptr<Watcher> watcher, + WatchNotifyFinalizer(scoped_refptr<Watch> watch, MojoResult result, const HandleSignalsState& state); WatchNotifyFinalizer(const WatchNotifyFinalizer& other); ~WatchNotifyFinalizer(); - scoped_refptr<Watcher> watcher; + scoped_refptr<Watch> watch; MojoResult result; HandleSignalsState state; }; - // Chosen by fair dice roll. - // - // TODO: We should measure the distribution of # of finalizers typical to - // any RequestContext and adjust this number accordingly. It's probably - // almost always 1, but 4 seems like a harmless upper bound for now. - static const size_t kStaticWatchFinalizersCapacity = 4; + // NOTE: This upper bound was chosen somewhat arbitrarily after observing some + // rare worst-case behavior in Chrome. A vast majority of RequestContexts only + // ever accumulate 0 or 1 finalizers. + static const size_t kStaticWatchFinalizersCapacity = 8; using WatchNotifyFinalizerList = base::StackVector<WatchNotifyFinalizer, kStaticWatchFinalizersCapacity>; using WatchCancelFinalizerList = - base::StackVector<scoped_refptr<Watcher>, kStaticWatchFinalizersCapacity>; + base::StackVector<scoped_refptr<Watch>, kStaticWatchFinalizersCapacity>; const Source source_;
diff --git a/mojo/edk/system/watch.cc b/mojo/edk/system/watch.cc new file mode 100644 index 0000000..cf08ac3 --- /dev/null +++ b/mojo/edk/system/watch.cc
@@ -0,0 +1,83 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/watch.h" + +#include "mojo/edk/system/request_context.h" +#include "mojo/edk/system/watcher_dispatcher.h" + +namespace mojo { +namespace edk { + +Watch::Watch(const scoped_refptr<WatcherDispatcher>& watcher, + const scoped_refptr<Dispatcher>& dispatcher, + uintptr_t context, + MojoHandleSignals signals) + : watcher_(watcher), + dispatcher_(dispatcher), + context_(context), + signals_(signals) {} + +bool Watch::NotifyState(const HandleSignalsState& state, + bool allowed_to_call_callback) { + AssertWatcherLockAcquired(); + + // NOTE: This method must NEVER call into |dispatcher_| directly, because it + // may be called while |dispatcher_| holds a lock. + + MojoResult rv = MOJO_RESULT_SHOULD_WAIT; + RequestContext* const request_context = RequestContext::current(); + if (state.satisfies(signals_)) { + rv = MOJO_RESULT_OK; + if (allowed_to_call_callback && rv != last_known_result_) { + request_context->AddWatchNotifyFinalizer(this, MOJO_RESULT_OK, state); + } + } else if (!state.can_satisfy(signals_)) { + rv = MOJO_RESULT_FAILED_PRECONDITION; + if (allowed_to_call_callback && rv != last_known_result_) { + request_context->AddWatchNotifyFinalizer( + this, MOJO_RESULT_FAILED_PRECONDITION, state); + } + } + + last_known_signals_state_ = + *static_cast<const MojoHandleSignalsState*>(&state); + last_known_result_ = rv; + return ready(); +} + +void Watch::Cancel() { + RequestContext::current()->AddWatchCancelFinalizer(this); +} + +void Watch::InvokeCallback(MojoResult result, + const HandleSignalsState& state, + MojoWatcherNotificationFlags flags) { + // We hold the lock through invocation to ensure that only one notification + // callback runs for this context at any given time. + base::AutoLock lock(notification_lock_); + if (result == MOJO_RESULT_CANCELLED) { + // Make sure cancellation is the last notification we dispatch. + DCHECK(!is_cancelled_); + is_cancelled_ = true; + } else if (is_cancelled_) { + return; + } + + // NOTE: This will acquire |watcher_|'s internal lock. It's safe because a + // thread can only enter InvokeCallback() from within a RequestContext + // destructor where no dispatcher locks are held. + watcher_->InvokeWatchCallback(context_, result, state, flags); +} + +Watch::~Watch() {} + +#if DCHECK_IS_ON() +void Watch::AssertWatcherLockAcquired() const { + watcher_->lock_.AssertAcquired(); +} +#endif + +} // namespace edk +} // namespace mojo
diff --git a/mojo/edk/system/watch.h b/mojo/edk/system/watch.h new file mode 100644 index 0000000..f277de9 --- /dev/null +++ b/mojo/edk/system/watch.h
@@ -0,0 +1,124 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_WATCH_H_ +#define MOJO_EDK_SYSTEM_WATCH_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "mojo/edk/system/atomic_flag.h" +#include "mojo/edk/system/handle_signals_state.h" + +namespace mojo { +namespace edk { + +class Dispatcher; +class WatcherDispatcher; + +// Encapsulates the state associated with a single watch context within a +// watcher. +// +// Every Watch has its own cancellation state, and is captured by RequestContext +// notification finalizers to avoid redundant context resolution during +// finalizer execution. +class Watch : public base::RefCountedThreadSafe<Watch> { + public: + // Constructs a Watch which represents a watch within |watcher| associated + // with |context|, watching |dispatcher| for |signals|. + Watch(const scoped_refptr<WatcherDispatcher>& watcher, + const scoped_refptr<Dispatcher>& dispatcher, + uintptr_t context, + MojoHandleSignals signals); + + // Notifies the Watch of a potential state change. + // + // If |allowed_to_call_callback| is true, this may add a notification + // finalizer to the current RequestContext to invoke the watcher's callback + // with this watch's context. See return values below. + // + // This is called directly by WatcherDispatcher whenever the Watch's observed + // dispatcher notifies the WatcherDispatcher of a state change. + // + // Returns |true| if the Watch entered or remains in a ready state as a result + // of the state change. If |allowed_to_call_callback| was true in this case, + // the Watch will have also attached a notification finalizer to the current + // RequestContext. + // + // Returns |false| if the + bool NotifyState(const HandleSignalsState& state, + bool allowed_to_call_callback); + + // Notifies the watch of cancellation ASAP. This will always be the last + // notification sent for the watch. + void Cancel(); + + // Finalizer method for RequestContexts. This method is invoked once for every + // notification finalizer added to a RequestContext by this object. This calls + // down into the WatcherDispatcher to do the actual notification call. + void InvokeCallback(MojoResult result, + const HandleSignalsState& state, + MojoWatcherNotificationFlags flags); + + const scoped_refptr<Dispatcher>& dispatcher() const { return dispatcher_; } + uintptr_t context() const { return context_; } + + MojoResult last_known_result() const { + AssertWatcherLockAcquired(); + return last_known_result_; + } + + MojoHandleSignalsState last_known_signals_state() const { + AssertWatcherLockAcquired(); + return last_known_signals_state_; + } + + bool ready() const { + AssertWatcherLockAcquired(); + return last_known_result_ == MOJO_RESULT_OK || + last_known_result_ == MOJO_RESULT_FAILED_PRECONDITION; + } + + private: + friend class base::RefCountedThreadSafe<Watch>; + + ~Watch(); + +#if DCHECK_IS_ON() + void AssertWatcherLockAcquired() const; +#else + void AssertWatcherLockAcquired() const {} +#endif + + const scoped_refptr<WatcherDispatcher> watcher_; + const scoped_refptr<Dispatcher> dispatcher_; + const uintptr_t context_; + const MojoHandleSignals signals_; + + // The result code with which this Watch would notify if currently armed, + // based on the last known signaling state of |dispatcher_|. Guarded by the + // owning WatcherDispatcher's lock. + MojoResult last_known_result_ = MOJO_RESULT_UNKNOWN; + + // The last known signaling state of |dispatcher_|. Guarded by the owning + // WatcherDispatcher's lock. + MojoHandleSignalsState last_known_signals_state_ = {0, 0}; + + // Guards |is_cancelled_| below and mutually excludes individual watch + // notification executions for this same watch context. + // + // Note that this should only be acquired from a RequestContext finalizer to + // ensure that no other internal locks are already held. + base::Lock notification_lock_; + + // Guarded by |notification_lock_|. + bool is_cancelled_ = false; + + DISALLOW_COPY_AND_ASSIGN(Watch); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_WATCH_H_
diff --git a/mojo/edk/system/watch_unittest.cc b/mojo/edk/system/watch_unittest.cc deleted file mode 100644 index ec28d94..0000000 --- a/mojo/edk/system/watch_unittest.cc +++ /dev/null
@@ -1,480 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <functional> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "mojo/edk/system/request_context.h" -#include "mojo/edk/test/mojo_test_base.h" -#include "mojo/public/c/system/functions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace edk { -namespace { - -void IgnoreResult(uintptr_t context, - MojoResult result, - MojoHandleSignalsState signals, - MojoWatchNotificationFlags flags) { -} - -// A test helper class for watching a handle. The WatchHelper instance is used -// as a watch context for a single watch callback. -class WatchHelper { - public: - using Callback = - std::function<void(MojoResult result, MojoHandleSignalsState state)>; - - WatchHelper() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} - ~WatchHelper() { - CHECK(!watching_); - } - - void Watch(MojoHandle handle, - MojoHandleSignals signals, - const Callback& callback) { - CHECK(!watching_); - - handle_ = handle; - callback_ = callback; - watching_ = true; - CHECK_EQ(MOJO_RESULT_OK, MojoWatch(handle_, signals, &WatchHelper::OnNotify, - reinterpret_cast<uintptr_t>(this))); - } - - bool is_watching() const { return watching_; } - - void Cancel() { - CHECK_EQ(MOJO_RESULT_OK, - MojoCancelWatch(handle_, reinterpret_cast<uintptr_t>(this))); - CHECK(watching_); - watching_ = false; - } - - private: - static void OnNotify(uintptr_t context, - MojoResult result, - MojoHandleSignalsState state, - MojoWatchNotificationFlags flags) { - WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); - watcher->task_runner_->PostTask( - FROM_HERE, - base::Bind(&NotifyOnMainThread, context, result, state, flags)); - } - - static void NotifyOnMainThread(uintptr_t context, - MojoResult result, - MojoHandleSignalsState state, - MojoWatchNotificationFlags flags) { - WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); - CHECK(watcher->watching_); - if (result == MOJO_RESULT_CANCELLED) - watcher->watching_ = false; - watcher->callback_(result, state); - } - - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - bool watching_ = false; - MojoHandle handle_; - Callback callback_; - - DISALLOW_COPY_AND_ASSIGN(WatchHelper); -}; - -class WatchTest : public test::MojoTestBase { - public: - WatchTest() {} - ~WatchTest() override {} - - protected: - - private: - base::MessageLoop message_loop_; - - DISALLOW_COPY_AND_ASSIGN(WatchTest); -}; - -TEST_F(WatchTest, NotifyBasic) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(b_watcher.is_watching()); - loop.Quit(); - }); - - WriteMessage(a, "Hello!"); - loop.Run(); - - EXPECT_TRUE(b_watcher.is_watching()); - b_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, NotifyUnsatisfiable) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - EXPECT_EQ(0u, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_EQ(0u, - state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(b_watcher.is_watching()); - loop.Quit(); - }); - - CloseHandle(a); - loop.Run(); - - b_watcher.Cancel(); - - CloseHandle(b); -} - -TEST_F(WatchTest, NotifyCancellation) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_CANCELLED, result); - EXPECT_EQ(0u, state.satisfied_signals); - EXPECT_EQ(0u, state.satisfiable_signals); - EXPECT_FALSE(b_watcher.is_watching()); - loop.Quit(); - }); - - CloseHandle(b); - loop.Run(); - - CloseHandle(a); -} - -TEST_F(WatchTest, InvalidArguemnts) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - uintptr_t context = reinterpret_cast<uintptr_t>(this); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, - &IgnoreResult, context)); - - // Can't cancel a watch that doesn't exist. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(a, ~context)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(b, context)); - - CloseHandle(a); - CloseHandle(b); - - // Can't watch a handle that doesn't exist. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); -} - -TEST_F(WatchTest, NoDuplicateContext) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - // Try to add the same watch twice; should fail. - uintptr_t context = reinterpret_cast<uintptr_t>(this); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, - &IgnoreResult, context)); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); - - // Cancel and add it again; should be OK. - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(a, context)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, - &IgnoreResult, context)); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, MultipleWatches) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - // Add multiple watchers to |b| and see that they are both notified by a - // single write to |a|. - base::RunLoop loop; - int expected_notifications = 2; - auto on_readable = [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_GT(expected_notifications, 0); - if (--expected_notifications == 0) - loop.Quit(); - }; - WatchHelper watcher1; - WatchHelper watcher2; - watcher1.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); - watcher2.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); - - WriteMessage(a, "Ping!"); - loop.Run(); - - watcher1.Cancel(); - watcher2.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, WatchWhileSatisfied) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - // Write to |a| and then start watching |b|. The callback should be invoked - // synchronously. - WriteMessage(a, "hey"); - bool signaled = false; - WatchHelper b_watcher; - base::RunLoop loop; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - signaled = true; - loop.Quit(); - }); - loop.Run(); - EXPECT_TRUE(signaled); - b_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, WatchWhileUnsatisfiable) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - // Close |a| and then try to watch |b|. MojoWatch() should fail. - CloseHandle(a); - uintptr_t context = reinterpret_cast<uintptr_t>(this); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); - - CloseHandle(b); -} - -TEST_F(WatchTest, RespondFromCallback) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - // Watch |a| and |b|. Write to |a|, then write to |b| from within the callback - // which notifies it of the available message. - const std::string kTestMessage = "hello worlds."; - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(b_watcher.is_watching()); - - // Echo a's message back to it. - WriteMessage(b, ReadMessage(b)); - }); - - WatchHelper a_watcher; - a_watcher.Watch( - a, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(a_watcher.is_watching()); - - // Expect to receive back the message that was originally sent to |b|. - EXPECT_EQ(kTestMessage, ReadMessage(a)); - - loop.Quit(); - }); - - WriteMessage(a, kTestMessage); - loop.Run(); - - a_watcher.Cancel(); - b_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, WatchDataPipeConsumer) { - MojoHandle a, b; - CreateDataPipe(&a, &b, 64); - - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(b_watcher.is_watching()); - loop.Quit(); - }); - - WriteData(a, "Hello!"); - loop.Run(); - - EXPECT_TRUE(b_watcher.is_watching()); - b_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, WatchDataPipeProducer) { - MojoHandle a, b; - CreateDataPipe(&a, &b, 8); - - // Fill the pipe to capacity so writes will block. - WriteData(a, "xxxxxxxx"); - - base::RunLoop loop; - WatchHelper a_watcher; - a_watcher.Watch( - a, MOJO_HANDLE_SIGNAL_WRITABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); - EXPECT_TRUE(a_watcher.is_watching()); - loop.Quit(); - }); - - EXPECT_EQ("xxxxxxxx", ReadData(b, 8)); - loop.Run(); - - EXPECT_TRUE(a_watcher.is_watching()); - a_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, WakeUpSelfWithinWatchCallback) { - MojoHandle a, b; - CreateMessagePipe(&a, &b); - - int expected_notifications = 2; - base::RunLoop loop; - WatchHelper b_watcher; - b_watcher.Watch( - b, MOJO_HANDLE_SIGNAL_READABLE, - [&] (MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, - state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_TRUE(b_watcher.is_watching()); - if (--expected_notifications == 0) { - loop.Quit(); - } else { - // Trigger b's watch again from within this callback. This should be - // safe to do. - WriteMessage(a, "hey"); - } - }); - - WriteMessage(a, "hey hey hey"); - loop.Run(); - - b_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(b); -} - -TEST_F(WatchTest, NestedCancellation) { - // Verifies that cancellations in nested system request contexts preempt - // other notifications for the same watcher. This tests against the condition - // hit by http://crbug.com/622298. - - MojoHandle a, b, c, d; - CreateMessagePipe(&a, &b); - CreateMessagePipe(&c, &d); - - base::RunLoop loop; - bool a_watcher_run = false; - WatchHelper a_watcher; - a_watcher.Watch( - a, MOJO_HANDLE_SIGNAL_READABLE, - [&](MojoResult result, MojoHandleSignalsState state) { - a_watcher_run = true; - }); - - WatchHelper c_watcher; - c_watcher.Watch( - c, MOJO_HANDLE_SIGNAL_READABLE, - [&](MojoResult result, MojoHandleSignalsState state) { - // This will trigger a notification on |a_watcher| above to be executed - // once this handler finishes running... - CloseHandle(b); - - // ...but this should prevent that notification from dispatching because - // |a_watcher| is now cancelled. - a_watcher.Cancel(); - - loop.Quit(); - }); - - { - // Force "system" notifications for the synchronous behavior required to - // test this case. - mojo::edk::RequestContext request_context( - mojo::edk::RequestContext::Source::SYSTEM); - - // Trigger the |c_watcher| callback above. - CloseHandle(d); - } - - loop.Run(); - - EXPECT_FALSE(a_watcher.is_watching()); - EXPECT_FALSE(a_watcher_run); - - c_watcher.Cancel(); - - CloseHandle(a); - CloseHandle(c); -} - -} // namespace -} // namespace edk -} // namespace mojo
diff --git a/mojo/edk/system/watcher.cc b/mojo/edk/system/watcher.cc deleted file mode 100644 index 25c227641..0000000 --- a/mojo/edk/system/watcher.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/edk/system/watcher.h" - -#include "mojo/edk/system/handle_signals_state.h" -#include "mojo/edk/system/request_context.h" - -namespace mojo { -namespace edk { - -Watcher::Watcher(MojoHandleSignals signals, const WatchCallback& callback) - : signals_(signals), callback_(callback) { -} - -void Watcher::MaybeInvokeCallback(MojoResult result, - const HandleSignalsState& state, - MojoWatchNotificationFlags flags) { - base::AutoLock lock(lock_); - if (is_cancelled_) - return; - - callback_.Run(result, state, flags); -} - -void Watcher::NotifyForStateChange(const HandleSignalsState& signals_state) { - RequestContext* request_context = RequestContext::current(); - if (signals_state.satisfies(signals_)) { - request_context->AddWatchNotifyFinalizer( - make_scoped_refptr(this), MOJO_RESULT_OK, signals_state); - } else if (!signals_state.can_satisfy(signals_)) { - request_context->AddWatchNotifyFinalizer( - make_scoped_refptr(this), MOJO_RESULT_FAILED_PRECONDITION, - signals_state); - } -} - -void Watcher::NotifyClosed() { - static const HandleSignalsState closed_state = {0, 0}; - RequestContext::current()->AddWatchNotifyFinalizer( - make_scoped_refptr(this), MOJO_RESULT_CANCELLED, closed_state); -} - -void Watcher::Cancel() { - base::AutoLock lock(lock_); - is_cancelled_ = true; -} - -Watcher::~Watcher() {} - -} // namespace edk -} // namespace mojo
diff --git a/mojo/edk/system/watcher.h b/mojo/edk/system/watcher.h deleted file mode 100644 index b6dc2e46..0000000 --- a/mojo/edk/system/watcher.h +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_EDK_SYSTEM_WATCHER_H_ -#define MOJO_EDK_SYSTEM_WATCHER_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "mojo/public/c/system/functions.h" -#include "mojo/public/c/system/types.h" - -namespace mojo { -namespace edk { - -struct HandleSignalsState; - -// This object corresponds to a watch added by a single call to |MojoWatch()|. -// -// An event may occur at any time which should trigger a Watcher to run its -// callback, but the callback needs to be deferred until all EDK locks are -// released. At the same time, a watch may be cancelled at any time by -// |MojoCancelWatch()| and it is not OK for the callback to be invoked after -// that happens. -// -// Therefore a Watcher needs to have some associated thread-safe state to track -// its cancellation, which is why it's ref-counted. -class Watcher : public base::RefCountedThreadSafe<Watcher> { - public: - using WatchCallback = base::Callback<void(MojoResult, - const HandleSignalsState&, - MojoWatchNotificationFlags)>; - - // Constructs a new Watcher which watches for |signals| to be satisfied on a - // handle and which invokes |callback| either when one such signal is - // satisfied, or all such signals become unsatisfiable. - Watcher(MojoHandleSignals signals, const WatchCallback& callback); - - // Runs the Watcher's callback with the given arguments if it hasn't been - // cancelled yet. - void MaybeInvokeCallback(MojoResult result, - const HandleSignalsState& state, - MojoWatchNotificationFlags flags); - - // Notifies the Watcher of a state change. This may result in the Watcher - // adding a finalizer to the current RequestContext to invoke its callback, - // cancellation notwithstanding. - void NotifyForStateChange(const HandleSignalsState& signals_state); - - // Notifies the Watcher of handle closure. This always results in the Watcher - // adding a finalizer to the current RequestContext to invoke its callback, - // cancellation notwithstanding. - void NotifyClosed(); - - // Explicitly cancels the watch, guaranteeing that its callback will never be - // be invoked again. - void Cancel(); - - private: - friend class base::RefCountedThreadSafe<Watcher>; - - ~Watcher(); - - // The set of signals which are watched by this Watcher. - const MojoHandleSignals signals_; - - // The callback to invoke with a result and signal state any time signals in - // |signals_| are satisfied or become permanently unsatisfiable. - const WatchCallback callback_; - - // Guards |is_cancelled_|. - base::Lock lock_; - - // Indicates whether the watch has been cancelled. A |Watcher| may exist for a - // brief period of time after being cancelled if it's been attached as a - // RequestContext finalizer. In such cases the callback must not be invoked, - // hence this flag. - bool is_cancelled_ = false; - - DISALLOW_COPY_AND_ASSIGN(Watcher); -}; - -} // namespace edk -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_WATCHER_H_
diff --git a/mojo/edk/system/watcher_dispatcher.cc b/mojo/edk/system/watcher_dispatcher.cc new file mode 100644 index 0000000..e4cc875 --- /dev/null +++ b/mojo/edk/system/watcher_dispatcher.cc
@@ -0,0 +1,219 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/watcher_dispatcher.h" + +#include <limits> +#include <map> + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "mojo/edk/system/watch.h" + +namespace mojo { +namespace edk { + +WatcherDispatcher::WatcherDispatcher(MojoWatcherCallback callback) + : callback_(callback) {} + +void WatcherDispatcher::NotifyHandleState(Dispatcher* dispatcher, + const HandleSignalsState& state) { + base::AutoLock lock(lock_); + auto it = watched_handles_.find(dispatcher); + if (it == watched_handles_.end()) + return; + + // Maybe fire a notification to the watch assoicated with this dispatcher, + // provided we're armed it cares about the new state. + if (it->second->NotifyState(state, armed_)) { + ready_watches_.insert(it->second.get()); + + // If we were armed and got here, we notified the watch. Disarm. + armed_ = false; + } else { + ready_watches_.erase(it->second.get()); + } +} + +void WatcherDispatcher::NotifyHandleClosed(Dispatcher* dispatcher) { + scoped_refptr<Watch> watch; + { + base::AutoLock lock(lock_); + auto it = watched_handles_.find(dispatcher); + if (it == watched_handles_.end()) + return; + + watch = std::move(it->second); + + // Wipe out all state associated with the closed dispatcher. + watches_.erase(watch->context()); + ready_watches_.erase(watch.get()); + watched_handles_.erase(it); + } + + // NOTE: It's important that this is called outside of |lock_| since it + // acquires internal Watch locks. + watch->Cancel(); +} + +void WatcherDispatcher::InvokeWatchCallback( + uintptr_t context, + MojoResult result, + const HandleSignalsState& state, + MojoWatcherNotificationFlags flags) { + { + // We avoid holding the lock during dispatch. It's OK for notification + // callbacks to close this watcher, and it's OK for notifications to race + // with closure, if for example the watcher is closed from another thread + // between this test and the invocation of |callback_| below. + // + // Because cancellation synchronously blocks all future notifications, and + // because notifications themselves are mutually exclusive for any given + // context, we still guarantee that a single MOJO_RESULT_CANCELLED result + // is the last notification received for any given context. + // + // This guarantee is sufficient to make safe, synchronized, per-context + // state management possible in user code. + base::AutoLock lock(lock_); + if (closed_ && result != MOJO_RESULT_CANCELLED) + return; + } + + callback_(context, result, static_cast<MojoHandleSignalsState>(state), flags); +} + +Dispatcher::Type WatcherDispatcher::GetType() const { + return Type::WATCHER; +} + +MojoResult WatcherDispatcher::Close() { + // We swap out all the watched handle information onto the stack so we can + // call into their dispatchers without our own lock held. + std::map<uintptr_t, scoped_refptr<Watch>> watches; + { + base::AutoLock lock(lock_); + DCHECK(!closed_); + closed_ = true; + std::swap(watches, watches_); + watched_handles_.clear(); + } + + // Remove all refs from our watched dispatchers and fire cancellations. + for (auto& entry : watches) { + entry.second->dispatcher()->RemoveWatcherRef(this, entry.first); + entry.second->Cancel(); + } + + return MOJO_RESULT_OK; +} + +MojoResult WatcherDispatcher::WatchDispatcher( + scoped_refptr<Dispatcher> dispatcher, + MojoHandleSignals signals, + uintptr_t context) { + // NOTE: Because it's critical to avoid acquiring any other dispatcher locks + // while |lock_| is held, we defer adding oursevles to the dispatcher until + // after we've updated all our own relevant state and released |lock_|. + { + base::AutoLock lock(lock_); + if (watches_.count(context) || watched_handles_.count(dispatcher.get())) + return MOJO_RESULT_ALREADY_EXISTS; + + scoped_refptr<Watch> watch = new Watch(this, dispatcher, context, signals); + watches_.insert({context, watch}); + auto result = + watched_handles_.insert(std::make_pair(dispatcher.get(), watch)); + DCHECK(result.second); + } + + MojoResult rv = dispatcher->AddWatcherRef(this, context); + if (rv != MOJO_RESULT_OK) { + // Oops. This was not a valid handle to watch. Undo the above work and + // fail gracefully. + base::AutoLock lock(lock_); + watches_.erase(context); + watched_handles_.erase(dispatcher.get()); + return rv; + } + + return MOJO_RESULT_OK; +} + +MojoResult WatcherDispatcher::CancelWatch(uintptr_t context) { + // We may remove the last stored ref to the Watch below, so we retain + // a reference on the stack. + scoped_refptr<Watch> watch; + { + base::AutoLock lock(lock_); + auto it = watches_.find(context); + if (it == watches_.end()) + return MOJO_RESULT_NOT_FOUND; + watch = it->second; + watches_.erase(it); + } + + // Mark the watch as cancelled so no further notifications get through. + watch->Cancel(); + + // We remove the watcher ref for this context before updating any more + // internal watcher state, ensuring that we don't receiving further + // notifications for this context. + watch->dispatcher()->RemoveWatcherRef(this, context); + + { + base::AutoLock lock(lock_); + auto handle_it = watched_handles_.find(watch->dispatcher().get()); + DCHECK(handle_it != watched_handles_.end()); + ready_watches_.erase(handle_it->second.get()); + watched_handles_.erase(handle_it); + } + + return MOJO_RESULT_OK; +} + +MojoResult WatcherDispatcher::Arm( + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) { + base::AutoLock lock(lock_); + if (num_ready_contexts && + (!ready_contexts || !ready_results || !ready_signals_states)) { + return MOJO_RESULT_INVALID_ARGUMENT; + } + + if (watched_handles_.empty()) + return MOJO_RESULT_NOT_FOUND; + + if (ready_watches_.empty()) { + // Fast path: No watches are ready to notify, so we're done. + armed_ = true; + return MOJO_RESULT_OK; + } + + if (num_ready_contexts) { + uint32_t max_ready_contexts = *num_ready_contexts; + *num_ready_contexts = 0; + for (auto& entry : watched_handles_) { + if (max_ready_contexts == *num_ready_contexts) + break; + + const Watch* watch = entry.second.get(); + if (!watch->ready()) + continue; + + *(ready_contexts++) = watch->context(); + *(ready_results++) = watch->last_known_result(); + *(ready_signals_states++) = watch->last_known_signals_state(); + ++(*num_ready_contexts); + } + } + + return MOJO_RESULT_FAILED_PRECONDITION; +} + +WatcherDispatcher::~WatcherDispatcher() {} + +} // namespace edk +} // namespace mojo
diff --git a/mojo/edk/system/watcher_dispatcher.h b/mojo/edk/system/watcher_dispatcher.h new file mode 100644 index 0000000..9698818 --- /dev/null +++ b/mojo/edk/system/watcher_dispatcher.h
@@ -0,0 +1,91 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_ +#define MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_ + +#include <map> +#include <set> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/system/handle_signals_state.h" +#include "mojo/edk/system/system_impl_export.h" +#include "mojo/public/c/system/watcher.h" + +namespace mojo { +namespace edk { + +class Watch; + +// The dispatcher type which backs watcher handles. +class WatcherDispatcher : public Dispatcher { + public: + // Constructs a new WatcherDispatcher which invokes |callback| when a + // registered watch observes some relevant state change. + explicit WatcherDispatcher(MojoWatcherCallback callback); + + // Methods used by watched dispatchers to notify watchers of events. + void NotifyHandleState(Dispatcher* dispatcher, + const HandleSignalsState& state); + void NotifyHandleClosed(Dispatcher* dispatcher); + + // Method used by RequestContext (indirectly, via Watch) to complete + // notification operations from a safe stack frame to avoid reentrancy. + void InvokeWatchCallback(uintptr_t context, + MojoResult result, + const HandleSignalsState& state, + MojoWatcherNotificationFlags flags); + + // Dispatcher: + Type GetType() const override; + MojoResult Close() override; + MojoResult WatchDispatcher(scoped_refptr<Dispatcher> dispatcher, + MojoHandleSignals signals, + uintptr_t context) override; + MojoResult CancelWatch(uintptr_t context) override; + MojoResult Arm(uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) override; + + private: + friend class Watch; + + ~WatcherDispatcher() override; + + const MojoWatcherCallback callback_; + + // Guards access to the fields below. + // + // NOTE: This may be acquired while holding another dispatcher's lock, as + // watched dispatchers call into WatcherDispatcher methods which lock this + // when issuing state change notifications. WatcherDispatcher must therefore + // take caution to NEVER acquire other dispatcher locks while this is held. + base::Lock lock_; + + bool armed_ = false; + bool closed_ = false; + + // A mapping from context to Watch. + std::map<uintptr_t, scoped_refptr<Watch>> watches_; + + // A mapping from watched dispatcher to Watch. + std::map<Dispatcher*, scoped_refptr<Watch>> watched_handles_; + + // The set of all Watch instances which are currently ready to signal. This is + // used for efficient arming behavior, as it allows for O(1) discovery of + // whether or not arming can succeed and quick determination of who's + // responsible if it can't. + std::set<Watch*> ready_watches_; + + DISALLOW_COPY_AND_ASSIGN(WatcherDispatcher); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_
diff --git a/mojo/edk/system/watcher_set.cc b/mojo/edk/system/watcher_set.cc index 878f29a..0355b58 100644 --- a/mojo/edk/system/watcher_set.cc +++ b/mojo/edk/system/watcher_set.cc
@@ -4,54 +4,79 @@ #include "mojo/edk/system/watcher_set.h" -#include "mojo/edk/system/request_context.h" -#include "mojo/public/c/system/types.h" +#include <utility> namespace mojo { namespace edk { -WatcherSet::WatcherSet() {} +WatcherSet::WatcherSet(Dispatcher* owner) : owner_(owner) {} -WatcherSet::~WatcherSet() {} +WatcherSet::~WatcherSet() = default; -void WatcherSet::NotifyForStateChange(const HandleSignalsState& state) { +void WatcherSet::NotifyState(const HandleSignalsState& state) { + // Avoid notifying watchers if they have already seen this state. + if (last_known_state_.has_value() && state.equals(last_known_state_.value())) + return; + last_known_state_ = state; for (const auto& entry : watchers_) - entry.second->NotifyForStateChange(state); + entry.first->NotifyHandleState(owner_, state); } void WatcherSet::NotifyClosed() { for (const auto& entry : watchers_) - entry.second->NotifyClosed(); + entry.first->NotifyHandleClosed(owner_); } -MojoResult WatcherSet::Add(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, +MojoResult WatcherSet::Add(const scoped_refptr<WatcherDispatcher>& watcher, uintptr_t context, const HandleSignalsState& current_state) { - auto it = watchers_.find(context); - if (it != watchers_.end()) + auto it = watchers_.find(watcher.get()); + if (it == watchers_.end()) { + auto result = + watchers_.insert(std::make_pair(watcher.get(), Entry{watcher})); + it = result.first; + } + + if (!it->second.contexts.insert(context).second) return MOJO_RESULT_ALREADY_EXISTS; - if (!current_state.can_satisfy(signals)) - return MOJO_RESULT_FAILED_PRECONDITION; - - scoped_refptr<Watcher> watcher(new Watcher(signals, callback)); - watchers_.insert(std::make_pair(context, watcher)); - - watcher->NotifyForStateChange(current_state); - + if (last_known_state_.has_value() && + !current_state.equals(last_known_state_.value())) { + // This new state may be relevant to everyone, in which case we just + // notify everyone. + NotifyState(current_state); + } else { + // Otherwise only notify the newly added Watcher. + watcher->NotifyHandleState(owner_, current_state); + } return MOJO_RESULT_OK; } -MojoResult WatcherSet::Remove(uintptr_t context) { - auto it = watchers_.find(context); +MojoResult WatcherSet::Remove(WatcherDispatcher* watcher, uintptr_t context) { + auto it = watchers_.find(watcher); if (it == watchers_.end()) - return MOJO_RESULT_INVALID_ARGUMENT; + return MOJO_RESULT_NOT_FOUND; - RequestContext::current()->AddWatchCancelFinalizer(it->second); - watchers_.erase(it); + ContextSet& contexts = it->second.contexts; + auto context_it = contexts.find(context); + if (context_it == contexts.end()) + return MOJO_RESULT_NOT_FOUND; + + contexts.erase(context_it); + if (contexts.empty()) + watchers_.erase(it); + return MOJO_RESULT_OK; } +WatcherSet::Entry::Entry(const scoped_refptr<WatcherDispatcher>& dispatcher) + : dispatcher(dispatcher) {} + +WatcherSet::Entry::Entry(Entry&& other) = default; + +WatcherSet::Entry::~Entry() = default; + +WatcherSet::Entry& WatcherSet::Entry::operator=(Entry&& other) = default; + } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/watcher_set.h b/mojo/edk/system/watcher_set.h index 8ae54a1b..2b7ef2c5a 100644 --- a/mojo/edk/system/watcher_set.h +++ b/mojo/edk/system/watcher_set.h
@@ -5,45 +5,62 @@ #ifndef MOJO_EDK_SYSTEM_WATCHER_SET_H_ #define MOJO_EDK_SYSTEM_WATCHER_SET_H_ -#include <unordered_map> +#include <map> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "mojo/edk/system/handle_signals_state.h" -#include "mojo/edk/system/watcher.h" -#include "mojo/public/c/system/types.h" +#include "mojo/edk/system/watcher_dispatcher.h" namespace mojo { namespace edk { -// A WatcherSet maintains a set of Watchers attached to a single handle and -// keyed on an arbitrary user context. +// A WatcherSet maintains a set of references to WatcherDispatchers to be +// notified when a handle changes state. +// +// Dispatchers which may be watched by a watcher should own a WatcherSet and +// notify it of all relevant state changes. class WatcherSet { public: - WatcherSet(); + // |owner| is the Dispatcher who owns this WatcherSet. + explicit WatcherSet(Dispatcher* owner); ~WatcherSet(); - // Notifies all Watchers of a state change. - void NotifyForStateChange(const HandleSignalsState& state); + // Notifies all watchers of the handle's current signals state. + void NotifyState(const HandleSignalsState& state); - // Notifies all Watchers that their watched handle has been closed. + // Notifies all watchers that this handle has been closed. void NotifyClosed(); - // Adds a new watcher to watch for signals in |signals| to be satisfied or - // unsatisfiable. |current_state| is the current signals state of the - // handle being watched. - MojoResult Add(MojoHandleSignals signals, - const Watcher::WatchCallback& callback, + // Adds a new watcher+context. + MojoResult Add(const scoped_refptr<WatcherDispatcher>& watcher, uintptr_t context, const HandleSignalsState& current_state); - // Removes a watcher from the set. - MojoResult Remove(uintptr_t context); + // Removes a watcher+context. + MojoResult Remove(WatcherDispatcher* watcher, uintptr_t context); private: - // A map of watchers keyed on context value. - std::unordered_map<uintptr_t, scoped_refptr<Watcher>> watchers_; + using ContextSet = std::set<uintptr_t>; + + struct Entry { + Entry(const scoped_refptr<WatcherDispatcher>& dispatcher); + Entry(Entry&& other); + ~Entry(); + + Entry& operator=(Entry&& other); + + scoped_refptr<WatcherDispatcher> dispatcher; + ContextSet contexts; + + private: + DISALLOW_COPY_AND_ASSIGN(Entry); + }; + + Dispatcher* const owner_; + std::map<WatcherDispatcher*, Entry> watchers_; + base::Optional<HandleSignalsState> last_known_state_; DISALLOW_COPY_AND_ASSIGN(WatcherSet); };
diff --git a/mojo/edk/system/watcher_unittest.cc b/mojo/edk/system/watcher_unittest.cc new file mode 100644 index 0000000..a3f2742 --- /dev/null +++ b/mojo/edk/system/watcher_unittest.cc
@@ -0,0 +1,1590 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdint.h> + +#include <map> +#include <memory> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/platform_thread.h" +#include "base/threading/simple_thread.h" +#include "base/time/time.h" +#include "mojo/edk/test/mojo_test_base.h" +#include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/c/system/types.h" +#include "mojo/public/c/system/watcher.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace edk { +namespace { + +using WatcherTest = test::MojoTestBase; + +class WatchHelper { + public: + using ContextCallback = + base::Callback<void(MojoResult, MojoHandleSignalsState)>; + + WatchHelper() {} + ~WatchHelper() {} + + MojoResult CreateWatcher(MojoHandle* handle) { + return MojoCreateWatcher(&Notify, handle); + } + + uintptr_t CreateContext(const ContextCallback& callback) { + return CreateContextWithCancel(callback, base::Closure()); + } + + uintptr_t CreateContextWithCancel(const ContextCallback& callback, + const base::Closure& cancel_callback) { + auto context = base::MakeUnique<NotificationContext>(callback); + NotificationContext* raw_context = context.get(); + raw_context->SetCancelCallback(base::Bind( + [](std::unique_ptr<NotificationContext> context, + const base::Closure& cancel_callback) { + if (cancel_callback) + cancel_callback.Run(); + }, + base::Passed(&context), cancel_callback)); + return reinterpret_cast<uintptr_t>(raw_context); + } + + private: + class NotificationContext { + public: + explicit NotificationContext(const ContextCallback& callback) + : callback_(callback) {} + + ~NotificationContext() {} + + void SetCancelCallback(const base::Closure& cancel_callback) { + cancel_callback_ = cancel_callback; + } + + void Notify(MojoResult result, MojoHandleSignalsState state) { + if (result == MOJO_RESULT_CANCELLED) + cancel_callback_.Run(); + else + callback_.Run(result, state); + } + + private: + const ContextCallback callback_; + base::Closure cancel_callback_; + + DISALLOW_COPY_AND_ASSIGN(NotificationContext); + }; + + static void Notify(uintptr_t context, + MojoResult result, + MojoHandleSignalsState state, + MojoWatcherNotificationFlags flags) { + reinterpret_cast<NotificationContext*>(context)->Notify(result, state); + } + + DISALLOW_COPY_AND_ASSIGN(WatchHelper); +}; + +class ThreadedRunner : public base::SimpleThread { + public: + explicit ThreadedRunner(const base::Closure& callback) + : SimpleThread("ThreadedRunner"), callback_(callback) {} + ~ThreadedRunner() override {} + + void Run() override { callback_.Run(); } + + private: + const base::Closure callback_; + + DISALLOW_COPY_AND_ASSIGN(ThreadedRunner); +}; + +void ExpectNoNotification(uintptr_t context, + MojoResult result, + MojoHandleSignalsState state, + MojoWatcherNotificationFlags flags) { + NOTREACHED(); +} + +void ExpectOnlyCancel(uintptr_t context, + MojoResult result, + MojoHandleSignalsState state, + MojoWatcherNotificationFlags flags) { + EXPECT_EQ(result, MOJO_RESULT_CANCELLED); +} + +TEST_F(WatcherTest, InvalidArguments) { + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoCreateWatcher(&ExpectNoNotification, nullptr)); + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w)); + + // Try to watch unwatchable handles. + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoWatch(w, w, MOJO_HANDLE_SIGNAL_READABLE, 0)); + MojoHandle buffer_handle = CreateBuffer(42); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoWatch(w, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE, 0)); + + // Try to cancel a watch on an invalid watcher handle. + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(buffer_handle, 0)); + + // Try to arm an invalid handle. + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + MojoArmWatcher(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmWatcher(buffer_handle, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(buffer_handle)); + + // Try to arm with a non-null count but at least one null output buffer. + uint32_t num_ready_contexts = 1; + uintptr_t ready_context; + MojoResult ready_result; + MojoHandleSignalsState ready_state; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmWatcher(w, &num_ready_contexts, nullptr, &ready_result, + &ready_state)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmWatcher(w, &num_ready_contexts, &ready_context, nullptr, + &ready_state)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmWatcher(w, &num_ready_contexts, &ready_context, + &ready_result, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, WatchMessagePipeReadable) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + int num_expected_notifications = 1; + const uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, int* expected_count, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_GT(*expected_count, 0); + *expected_count -= 1; + + EXPECT_EQ(MOJO_RESULT_OK, result); + event->Signal(); + }, + &event, &num_expected_notifications)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + const char kMessage1[] = "hey hey hey hey"; + const char kMessage2[] = "i said hey"; + const char kMessage3[] = "what's goin' on?"; + + // Writing to |b| multiple times should notify exactly once. + WriteMessage(b, kMessage1); + WriteMessage(b, kMessage2); + event.Wait(); + + // This also shouldn't fire a notification; the watcher is still disarmed. + WriteMessage(b, kMessage3); + + // Arming should fail with relevant information. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(readable_a_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + + // Flush the three messages from above. + EXPECT_EQ(kMessage1, ReadMessage(a)); + EXPECT_EQ(kMessage2, ReadMessage(a)); + EXPECT_EQ(kMessage3, ReadMessage(a)); + + // Now we can rearm the watcher. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); +} + +TEST_F(WatcherTest, CloseWatchedMessagePipeHandle) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t readable_a_context = helper.CreateContextWithCancel( + WatchHelper::ContextCallback(), + base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + + // Test that closing a watched handle fires an appropriate notification, even + // when the watcher is unarmed. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, CloseWatchedMessagePipeHandlePeer) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + event->Signal(); + }, + &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + + // Test that closing a watched handle's peer with an armed watcher fires an + // appropriate notification. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + event.Wait(); + + // And now arming should fail with correct information about |a|'s state. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(readable_a_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & + MOJO_HANDLE_SIGNAL_PEER_CLOSED); + EXPECT_FALSE(ready_states[0].satisfiable_signals & + MOJO_HANDLE_SIGNAL_READABLE); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); +} + +TEST_F(WatcherTest, WatchDataPipeConsumerReadable) { + constexpr size_t kTestPipeCapacity = 64; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + int num_expected_notifications = 1; + const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, int* expected_count, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_GT(*expected_count, 0); + *expected_count -= 1; + + EXPECT_EQ(MOJO_RESULT_OK, result); + event->Signal(); + }, + &event, &num_expected_notifications)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, + readable_consumer_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + const char kMessage1[] = "hey hey hey hey"; + const char kMessage2[] = "i said hey"; + const char kMessage3[] = "what's goin' on?"; + + // Writing to |producer| multiple times should notify exactly once. + WriteData(producer, kMessage1); + WriteData(producer, kMessage2); + event.Wait(); + + // This also shouldn't fire a notification; the watcher is still disarmed. + WriteData(producer, kMessage3); + + // Arming should fail with relevant information. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(readable_consumer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + + // Flush the three messages from above. + EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1)); + EXPECT_EQ(kMessage2, ReadData(consumer, sizeof(kMessage2) - 1)); + EXPECT_EQ(kMessage3, ReadData(consumer, sizeof(kMessage3) - 1)); + + // Now we can rearm the watcher. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); +} + +TEST_F(WatcherTest, WatchDataPipeConsumerNewDataReadable) { + constexpr size_t kTestPipeCapacity = 64; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + int num_new_data_notifications = 0; + const uintptr_t new_data_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, int* notification_count, MojoResult result, + MojoHandleSignalsState state) { + *notification_count += 1; + + EXPECT_EQ(MOJO_RESULT_OK, result); + event->Signal(); + }, + &event, &num_new_data_notifications)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, + new_data_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + const char kMessage1[] = "hey hey hey hey"; + const char kMessage2[] = "i said hey"; + const char kMessage3[] = "what's goin' on?"; + + // Writing to |producer| multiple times should notify exactly once. + WriteData(producer, kMessage1); + WriteData(producer, kMessage2); + event.Wait(); + + // This also shouldn't fire a notification; the watcher is still disarmed. + WriteData(producer, kMessage3); + + // Arming should fail with relevant information. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(new_data_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + + // Attempt to read more data than is available. Should fail but clear the + // NEW_DATA_READABLE signal. + char large_buffer[512]; + uint32_t large_read_size = 512; + EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, + MojoReadData(consumer, large_buffer, &large_read_size, + MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + + // Attempt to arm again. Should succeed. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Write more data. Should notify. + event.Reset(); + WriteData(producer, kMessage1); + event.Wait(); + + // Reading some data should clear NEW_DATA_READABLE again so we can rearm. + EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + EXPECT_EQ(2, num_new_data_notifications); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); +} + +TEST_F(WatcherTest, WatchDataPipeProducerWritable) { + constexpr size_t kTestPipeCapacity = 8; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + // Half the capacity of the data pipe. + const char kTestData[] = "aaaa"; + static_assert((sizeof(kTestData) - 1) * 2 == kTestPipeCapacity, + "Invalid test data for this test."); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + int num_expected_notifications = 1; + const uintptr_t writable_producer_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, int* expected_count, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_GT(*expected_count, 0); + *expected_count -= 1; + + EXPECT_EQ(MOJO_RESULT_OK, result); + event->Signal(); + }, + &event, &num_expected_notifications)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + writable_producer_context)); + + // The producer is already writable, so arming should fail with relevant + // information. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(writable_producer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + // Write some data, but don't fill the pipe yet. Arming should fail again. + WriteData(producer, kTestData); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(writable_producer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + // Write more data, filling the pipe to capacity. Arming should succeed now. + WriteData(producer, kTestData); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Now read from the pipe, making the producer writable again. Should notify. + EXPECT_EQ(kTestData, ReadData(consumer, sizeof(kTestData) - 1)); + event.Wait(); + + // Arming should fail again. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(writable_producer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + // Fill the pipe once more and arm the watcher. Should succeed. + WriteData(producer, kTestData); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); +}; + +TEST_F(WatcherTest, CloseWatchedDataPipeConsumerHandle) { + constexpr size_t kTestPipeCapacity = 8; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t readable_consumer_context = helper.CreateContextWithCancel( + WatchHelper::ContextCallback(), + base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, + readable_consumer_context)); + + // Closing the consumer should fire a cancellation notification. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, CloseWatcherDataPipeConsumerHandlePeer) { + constexpr size_t kTestPipeCapacity = 8; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + event->Signal(); + }, + &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, + readable_consumer_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Closing the producer should fire a notification for an unsatisfiable watch. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + event.Wait(); + + // Now attempt to rearm and expect appropriate error feedback. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(readable_consumer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); + EXPECT_FALSE(ready_states[0].satisfiable_signals & + MOJO_HANDLE_SIGNAL_READABLE); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); +} + +TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandle) { + constexpr size_t kTestPipeCapacity = 8; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t writable_producer_context = helper.CreateContextWithCancel( + WatchHelper::ContextCallback(), + base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + writable_producer_context)); + + // Closing the consumer should fire a cancellation notification. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandlePeer) { + constexpr size_t kTestPipeCapacity = 8; + MojoHandle producer, consumer; + CreateDataPipe(&producer, &consumer, kTestPipeCapacity); + + const char kTestMessageFullCapacity[] = "xxxxxxxx"; + static_assert(sizeof(kTestMessageFullCapacity) - 1 == kTestPipeCapacity, + "Invalid test message size for this test."); + + // Make the pipe unwritable initially. + WriteData(producer, kTestMessageFullCapacity); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + const uintptr_t writable_producer_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + event->Signal(); + }, + &event)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + writable_producer_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Closing the consumer should fire a notification for an unsatisfiable watch, + // as the full data pipe can never be read from again and is therefore + // permanently full and unwritable. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); + event.Wait(); + + // Now attempt to rearm and expect appropriate error feedback. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(writable_producer_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); + EXPECT_FALSE(ready_states[0].satisfiable_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); +} + +TEST_F(WatcherTest, ArmWithNoWatches) { + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w)); + EXPECT_EQ(MOJO_RESULT_NOT_FOUND, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, WatchDuplicateContext) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0)); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, 0)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); +} + +TEST_F(WatcherTest, CancelUnknownWatch) { + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w)); + EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoCancelWatch(w, 1234)); +} + +TEST_F(WatcherTest, ArmWithWatchAlreadySatisfied) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_WRITABLE, 0)); + + // |a| is always writable, so we can never arm this watcher. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(0u, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); +} + +TEST_F(WatcherTest, ArmWithWatchAlreadyUnsatisfiable) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + + // |b| is closed and never wrote any messages, so |a| won't be readable again. + // MojoArmWatcher() should fail, incidcating as much. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = kMaxReadyContexts; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(0u, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & + MOJO_HANDLE_SIGNAL_PEER_CLOSED); + EXPECT_FALSE(ready_states[0].satisfiable_signals & + MOJO_HANDLE_SIGNAL_READABLE); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); +} + +TEST_F(WatcherTest, MultipleWatches) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + base::WaitableEvent a_event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent b_event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + WatchHelper helper; + int num_a_notifications = 0; + int num_b_notifications = 0; + auto notify_callback = + base::Bind([](base::WaitableEvent* event, int* notification_count, + MojoResult result, MojoHandleSignalsState state) { + *notification_count += 1; + EXPECT_EQ(MOJO_RESULT_OK, result); + event->Signal(); + }); + uintptr_t readable_a_context = helper.CreateContext( + base::Bind(notify_callback, &a_event, &num_a_notifications)); + uintptr_t readable_b_context = helper.CreateContext( + base::Bind(notify_callback, &b_event, &num_b_notifications)); + + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + // Add two independent watch contexts to watch for |a| or |b| readability. + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + const char kMessage1[] = "things are happening"; + const char kMessage2[] = "ok. ok. ok. ok."; + const char kMessage3[] = "plz wake up"; + + // Writing to |b| should signal |a|'s watch. + WriteMessage(b, kMessage1); + a_event.Wait(); + a_event.Reset(); + + // Subsequent messages on |b| should not trigger another notification. + WriteMessage(b, kMessage2); + WriteMessage(b, kMessage3); + + // Messages on |a| also shouldn't trigger |b|'s notification, since the + // watcher should be disarmed by now. + WriteMessage(a, kMessage1); + WriteMessage(a, kMessage2); + WriteMessage(a, kMessage3); + + // Arming should fail. Since we only ask for at most one context's information + // that's all we should get back. Which one we get is unspecified. + constexpr size_t kMaxReadyContexts = 10; + uint32_t num_ready_contexts = 1; + uintptr_t ready_contexts[kMaxReadyContexts]; + MojoResult ready_results[kMaxReadyContexts]; + MojoHandleSignalsState ready_states[kMaxReadyContexts]; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_TRUE(ready_contexts[0] == readable_a_context || + ready_contexts[0] == readable_b_context); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + // Now try arming again, verifying that both contexts are returned. + num_ready_contexts = kMaxReadyContexts; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(2u, num_ready_contexts); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[1]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + EXPECT_TRUE(ready_states[1].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + EXPECT_TRUE((ready_contexts[0] == readable_a_context && + ready_contexts[1] == readable_b_context) || + (ready_contexts[0] == readable_b_context && + ready_contexts[1] == readable_a_context)); + + // Flush out the test messages so we should be able to successfully rearm. + EXPECT_EQ(kMessage1, ReadMessage(a)); + EXPECT_EQ(kMessage2, ReadMessage(a)); + EXPECT_EQ(kMessage3, ReadMessage(a)); + EXPECT_EQ(kMessage1, ReadMessage(b)); + EXPECT_EQ(kMessage2, ReadMessage(b)); + EXPECT_EQ(kMessage3, ReadMessage(b)); + + // Add a watch which is always satisfied, so we can't arm. Arming should fail + // with only this new watch's information. + uintptr_t writable_c_context = helper.CreateContext(base::Bind( + [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); })); + MojoHandle c, d; + CreateMessagePipe(&c, &d); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, c, MOJO_HANDLE_SIGNAL_WRITABLE, writable_c_context)); + num_ready_contexts = kMaxReadyContexts; + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoArmWatcher(w, &num_ready_contexts, ready_contexts, + ready_results, ready_states)); + EXPECT_EQ(1u, num_ready_contexts); + EXPECT_EQ(writable_c_context, ready_contexts[0]); + EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + + // Cancel the new watch and arming should succeed once again. + EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, writable_c_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); +} + +TEST_F(WatcherTest, NotifyOtherFromNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hello a"; + static const char kTestMessageToB[] = "hello b"; + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + WatchHelper helper; + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](MojoHandle w, MojoHandle a, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ("hello a", ReadMessage(a)); + + // Re-arm the watcher and signal |b|. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + WriteMessage(a, kTestMessageToB); + }, + w, a)); + + uintptr_t readable_b_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoHandle w, MojoHandle b, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToB, ReadMessage(b)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + event->Signal(); + }, + &event, w, b)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Send a message to |a|. The relevant watch context should be notified, and + // should in turn send a message to |b|, waking up the other context. The + // second context signals |event|. + WriteMessage(b, kTestMessageToA); + event.Wait(); +} + +TEST_F(WatcherTest, NotifySelfFromNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hello a"; + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + WatchHelper helper; + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + int expected_notifications = 10; + uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](int* expected_count, MojoHandle w, MojoHandle a, MojoHandle b, + base::WaitableEvent* event, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ("hello a", ReadMessage(a)); + + EXPECT_GT(*expected_count, 0); + *expected_count -= 1; + if (*expected_count == 0) { + event->Signal(); + return; + } else { + // Re-arm the watcher and signal |a| again. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + WriteMessage(b, kTestMessageToA); + } + }, + &expected_notifications, w, a, b, &event)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Send a message to |a|. When the watch above is notified, it will rearm and + // send another message to |a|. This will happen until + // |expected_notifications| reaches 0. + WriteMessage(b, kTestMessageToA); + event.Wait(); +} + +TEST_F(WatcherTest, ImplicitCancelOtherFromNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle c, d; + CreateMessagePipe(&c, &d); + + static const char kTestMessageToA[] = "hi a"; + static const char kTestMessageToC[] = "hi c"; + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + WatchHelper helper; + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + uintptr_t readable_a_context = helper.CreateContextWithCancel( + base::Bind([](MojoResult result, MojoHandleSignalsState state) { + NOTREACHED(); + }), + base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + + uintptr_t readable_c_context = helper.CreateContext(base::Bind( + [](MojoHandle w, MojoHandle a, MojoHandle b, MojoHandle c, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToC, ReadMessage(c)); + + // Now rearm the watcher. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Must result in exactly ONE notification on the above context, for + // CANCELLED only. Because we cannot dispatch notifications until the + // stack unwinds, and because we must never dispatch non-cancellation + // notifications for a handle once it's been closed, we must be certain + // that cancellation due to closure preemptively invalidates any + // pending non-cancellation notifications queued on the current + // RequestContext, such as the one resulting from the WriteMessage here. + WriteMessage(b, kTestMessageToA); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + + // Rearming should be fine since |a|'s watch should already be + // implicitly cancelled (even though the notification will not have + // been invoked yet.) + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Nothing interesting should happen as a result of this. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + }, + w, a, b, c)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(d, kTestMessageToC); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); +} + +TEST_F(WatcherTest, ExplicitCancelOtherFromNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle c, d; + CreateMessagePipe(&c, &d); + + static const char kTestMessageToA[] = "hi a"; + static const char kTestMessageToC[] = "hi c"; + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + WatchHelper helper; + MojoHandle w; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); })); + + uintptr_t readable_c_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, uintptr_t readable_a_context, MojoHandle w, + MojoHandle a, MojoHandle b, MojoHandle c, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToC, ReadMessage(c)); + + // Now rearm the watcher. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Should result in no notifications on the above context, because the + // watch will have been cancelled by the time the notification callback + // can execute. + WriteMessage(b, kTestMessageToA); + WriteMessage(b, kTestMessageToA); + EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); + + // Rearming should be fine now. + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // Nothing interesting should happen as a result of these. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + + event->Signal(); + }, + &event, readable_a_context, w, a, b, c)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(d, kTestMessageToC); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); +} + +TEST_F(WatcherTest, NestedCancellation) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle c, d; + CreateMessagePipe(&c, &d); + + static const char kTestMessageToA[] = "hey a"; + static const char kTestMessageToC[] = "hey c"; + static const char kTestMessageToD[] = "hey d"; + + // This is a tricky test. It establishes a watch on |b| using one watcher and + // watches on |c| and |d| using another watcher. + // + // A message is written to |d| to wake up |c|'s watch, and the notification + // handler for that event does the following: + // 1. Writes to |a| to eventually wake up |b|'s watcher. + // 2. Rearms |c|'s watcher. + // 3. Writes to |d| to eventually wake up |c|'s watcher again. + // + // Meanwhile, |b|'s watch notification handler cancels |c|'s watch altogether + // before writing to |c| to wake up |d|. + // + // The net result should be that |c|'s context only gets notified once (from + // the first write to |d| above) and everyone else gets notified as expected. + + MojoHandle b_watcher; + MojoHandle cd_watcher; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher)); + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&cd_watcher)); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + uintptr_t readable_d_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoHandle d, MojoResult result, + MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToD, ReadMessage(d)); + event->Signal(); + }, + &event, d)); + + static int num_expected_c_notifications = 1; + uintptr_t readable_c_context = helper.CreateContext(base::Bind( + [](MojoHandle cd_watcher, MojoHandle a, MojoHandle c, MojoHandle d, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_GT(num_expected_c_notifications--, 0); + + // Trigger an eventual |readable_b_context| notification. + WriteMessage(a, kTestMessageToA); + + EXPECT_EQ(kTestMessageToC, ReadMessage(c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr, + nullptr, nullptr)); + + // Trigger another eventual |readable_c_context| notification. + WriteMessage(d, kTestMessageToC); + }, + cd_watcher, a, c, d)); + + uintptr_t readable_b_context = helper.CreateContext(base::Bind( + [](MojoHandle cd_watcher, uintptr_t readable_c_context, MojoHandle c, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, + MojoCancelWatch(cd_watcher, readable_c_context)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr, + nullptr, nullptr)); + + WriteMessage(c, kTestMessageToD); + }, + cd_watcher, readable_c_context, c)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE, + readable_b_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(cd_watcher, c, MOJO_HANDLE_SIGNAL_READABLE, + readable_c_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(cd_watcher, d, MOJO_HANDLE_SIGNAL_READABLE, + readable_d_context)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(cd_watcher, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(d, kTestMessageToC); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_watcher)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); +} + +TEST_F(WatcherTest, CancelSelfInNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hey a"; + + MojoHandle w; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + static uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + + // There should be no problem cancelling this watch from its own + // notification invocation. + EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + + // Arming should fail because there are no longer any registered + // watches on the watcher. + EXPECT_EQ(MOJO_RESULT_NOT_FOUND, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // And closing |a| should be fine (and should not invoke this + // notification with MOJO_RESULT_CANCELLED) for the same reason. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + + event->Signal(); + }, + &event, w, a)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(b, kTestMessageToA); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, CloseWatcherInNotificationCallback) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA1[] = "hey a"; + static const char kTestMessageToA2[] = "hey a again"; + + MojoHandle w; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, MojoHandle b, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToA1, ReadMessage(a)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // There should be no problem closing this watcher from its own + // notification callback. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + + // And these should not trigger more notifications, because |w| has been + // closed already. + WriteMessage(b, kTestMessageToA2); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + + event->Signal(); + }, + &event, w, a, b)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(b, kTestMessageToA1); + event.Wait(); +} + +TEST_F(WatcherTest, CloseWatcherAfterImplicitCancel) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hey a"; + + MojoHandle w; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + uintptr_t readable_a_context = helper.CreateContext(base::Bind( + [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + // This will cue up a notification for |MOJO_RESULT_CANCELLED|... + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + + // ...but it should never fire because we close the watcher here. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + + event->Signal(); + }, + &event, w, a)); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(b, kTestMessageToA); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); +} + +TEST_F(WatcherTest, OtherThreadCancelDuringNotification) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hey a"; + + MojoHandle w; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + base::WaitableEvent wait_for_notification( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + base::WaitableEvent wait_for_cancellation( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + static bool callback_done = false; + uintptr_t readable_a_context = helper.CreateContextWithCancel( + base::Bind( + [](base::WaitableEvent* wait_for_notification, MojoHandle w, + MojoHandle a, MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + + wait_for_notification->Signal(); + + // Give the other thread sufficient time to race with the completion + // of this callback. There should be no race, since the cancellation + // notification must be mutually exclusive to this notification. + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); + + callback_done = true; + }, + &wait_for_notification, w, a), + base::Bind( + [](base::WaitableEvent* wait_for_cancellation) { + EXPECT_TRUE(callback_done); + wait_for_cancellation->Signal(); + }, + &wait_for_cancellation)); + + ThreadedRunner runner(base::Bind( + [](base::WaitableEvent* wait_for_notification, + base::WaitableEvent* wait_for_cancellation, MojoHandle w, + uintptr_t readable_a_context) { + wait_for_notification->Wait(); + + // Cancel the watch while the notification is still running. + EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); + + wait_for_cancellation->Wait(); + + EXPECT_TRUE(callback_done); + }, + &wait_for_notification, &wait_for_cancellation, w, readable_a_context)); + runner.Start(); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + + WriteMessage(b, kTestMessageToA); + runner.Join(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +} + +TEST_F(WatcherTest, WatchesCancelEachOtherFromNotifications) { + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + static const char kTestMessageToA[] = "hey a"; + static const char kTestMessageToB[] = "hey b"; + + base::WaitableEvent wait_for_a_to_notify( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait_for_b_to_notify( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait_for_a_to_cancel( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait_for_b_to_cancel( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + MojoHandle a_watcher; + MojoHandle b_watcher; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&a_watcher)); + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher)); + + // We set up two watchers, one on |a| and one on |b|. They cancel each other + // from within their respective watch notifications. This should be safe, + // i.e., it should not deadlock, in spite of the fact that we also guarantee + // mutually exclusive notification execution (including cancellations) on any + // given watch. + bool a_cancelled = false; + bool b_cancelled = false; + static uintptr_t readable_b_context; + uintptr_t readable_a_context = helper.CreateContextWithCancel( + base::Bind( + [](base::WaitableEvent* wait_for_a_to_notify, + base::WaitableEvent* wait_for_b_to_notify, MojoHandle b_watcher, + MojoHandle a, MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + wait_for_a_to_notify->Signal(); + wait_for_b_to_notify->Wait(); + EXPECT_EQ(MOJO_RESULT_OK, + MojoCancelWatch(b_watcher, readable_b_context)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher)); + }, + &wait_for_a_to_notify, &wait_for_b_to_notify, b_watcher, a), + base::Bind( + [](base::WaitableEvent* wait_for_a_to_cancel, + base::WaitableEvent* wait_for_b_to_cancel, bool* a_cancelled) { + *a_cancelled = true; + wait_for_a_to_cancel->Signal(); + wait_for_b_to_cancel->Wait(); + }, + &wait_for_a_to_cancel, &wait_for_b_to_cancel, &a_cancelled)); + + readable_b_context = helper.CreateContextWithCancel( + base::Bind( + [](base::WaitableEvent* wait_for_a_to_notify, + base::WaitableEvent* wait_for_b_to_notify, + uintptr_t readable_a_context, MojoHandle a_watcher, MojoHandle b, + MojoResult result, MojoHandleSignalsState state) { + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(kTestMessageToB, ReadMessage(b)); + wait_for_b_to_notify->Signal(); + wait_for_a_to_notify->Wait(); + EXPECT_EQ(MOJO_RESULT_OK, + MojoCancelWatch(a_watcher, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_watcher)); + }, + &wait_for_a_to_notify, &wait_for_b_to_notify, readable_a_context, + a_watcher, b), + base::Bind( + [](base::WaitableEvent* wait_for_a_to_cancel, + base::WaitableEvent* wait_for_b_to_cancel, bool* b_cancelled) { + *b_cancelled = true; + wait_for_b_to_cancel->Signal(); + wait_for_a_to_cancel->Wait(); + }, + &wait_for_a_to_cancel, &wait_for_b_to_cancel, &b_cancelled)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a_watcher, a, MOJO_HANDLE_SIGNAL_READABLE, + readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(a_watcher, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE, + readable_b_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr)); + + ThreadedRunner runner( + base::Bind([](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b)); + runner.Start(); + + WriteMessage(a, kTestMessageToB); + + wait_for_a_to_cancel.Wait(); + wait_for_b_to_cancel.Wait(); + runner.Join(); + + EXPECT_TRUE(a_cancelled); + EXPECT_TRUE(b_cancelled); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); +} + +TEST_F(WatcherTest, AlwaysCancel) { + // Basic sanity check to ensure that all possible ways to cancel a watch + // result in a final MOJO_RESULT_CANCELLED notification. + + MojoHandle a, b; + CreateMessagePipe(&a, &b); + + MojoHandle w; + WatchHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + const base::Closure signal_event = + base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)); + + // Cancel via |MojoCancelWatch()|. + uintptr_t context = helper.CreateContextWithCancel( + WatchHelper::ContextCallback(), signal_event); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context)); + EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, context)); + event.Wait(); + event.Reset(); + + // Cancel by closing the watched handle. + context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(), + signal_event); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); + event.Wait(); + event.Reset(); + + // Cancel by closing the watcher handle. + context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(), + signal_event); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, context)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + event.Wait(); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); +} + +} // namespace +} // namespace edk +} // namespace mojo
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn index c3b3d5f..7b971e0 100644 --- a/mojo/public/c/system/BUILD.gn +++ b/mojo/public/c/system/BUILD.gn
@@ -18,6 +18,7 @@ "thunks.h", "types.h", "wait_set.h", + "watcher.h", ] defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
diff --git a/mojo/public/c/system/core.h b/mojo/public/c/system/core.h index 77d452b0..80a2e9a 100644 --- a/mojo/public/c/system/core.h +++ b/mojo/public/c/system/core.h
@@ -18,5 +18,6 @@ #include "mojo/public/c/system/system_export.h" #include "mojo/public/c/system/types.h" #include "mojo/public/c/system/wait_set.h" +#include "mojo/public/c/system/watcher.h" #endif // MOJO_PUBLIC_C_SYSTEM_CORE_H_
diff --git a/mojo/public/c/system/functions.h b/mojo/public/c/system/functions.h index f0a23d9..750a29ee 100644 --- a/mojo/public/c/system/functions.h +++ b/mojo/public/c/system/functions.h
@@ -19,14 +19,6 @@ extern "C" { #endif -// A callback used to notify watchers registered via |MojoWatch()|. Called when -// some watched signals are satisfied or become unsatisfiable. See the -// documentation for |MojoWatch()| for more details. -typedef void (*MojoWatchCallback)(uintptr_t context, - MojoResult result, - struct MojoHandleSignalsState signals_state, - MojoWatchNotificationFlags flags); - // Note: Pointer parameters that are labelled "optional" may be null (at least // under some circumstances). Non-const pointer parameters are also labeled // "in", "out", or "in/out", to indicate how they are used. (Note that how/if @@ -138,74 +130,6 @@ uint32_t* result_index, // Optional out struct MojoHandleSignalsState* signals_states); // Optional out -// Watches the given handle for one of the following events to happen: -// - A signal indicated by |signals| is satisfied. -// - It becomes known that no signal indicated by |signals| will ever be -// satisfied. (See the description of the |MOJO_RESULT_CANCELLED| and -// |MOJO_RESULT_FAILED_PRECONDITION| return values below.) -// - The handle is closed. -// -// |handle|: The handle to watch. Must be an open message pipe or data pipe -// handle. -// |signals|: The signals to watch for. -// |callback|: A function to be called any time one of the above events happens. -// The function must be safe to call from any thread at any time. -// |context|: User-provided context passed to |callback| when called. |context| -// is used to uniquely identify a registered watch and can be used to cancel -// the watch later using |MojoCancelWatch()|. -// -// Returns: -// |MOJO_RESULT_OK| if the watch has been successfully registered. Note that -// if the signals are already satisfied this may synchronously invoke -// |callback| before returning. -// |MOJO_RESULT_CANCELLED| if the watch was cancelled. In this case it is not -// necessary to explicitly call |MojoCancelWatch()|, and in fact it may be -// an error to do so as the handle may have been closed. -// |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not an open message pipe -// handle. -// |MOJO_RESULT_FAILED_PRECONDITION| if it is already known that |signals| can -// never be satisfied. -// |MOJO_RESULT_ALREADY_EXISTS| if there is already a watch registered for -// the same combination of |handle| and |context|. -// -// Callback result codes: -// The callback may be called at any time on any thread with one of the -// following result codes to indicate various events: -// -// |MOJO_RESULT_OK| indicates that some signal in |signals| has been -// satisfied. -// |MOJO_RESULT_FAILED_PRECONDITION| indicates that no signals in |signals| -// can ever be satisfied again. -// |MOJO_RESULT_CANCELLED| indicates that the handle has been closed. In this -// case the watch is implicitly cancelled and there is no need to call -// |MojoCancelWatch()|. -MOJO_SYSTEM_EXPORT MojoResult -MojoWatch(MojoHandle handle, - MojoHandleSignals signals, - MojoWatchCallback callback, - uintptr_t context); - -// Cancels a handle watch corresponding to some prior call to |MojoWatch()|. -// -// NOTE: If the watch callback corresponding to |context| is currently running -// this will block until the callback completes execution. It is therefore -// illegal to call |MojoCancelWatch()| on a given |handle| and |context| from -// within the associated callback itself, as this will always deadlock. -// -// After |MojoCancelWatch()| function returns, the watch's associated callback -// will NEVER be called again by Mojo. -// -// |context|: The same user-provided context given to some prior call to -// |MojoWatch()|. Only the watch corresponding to this context will be -// cancelled. -// -// Returns: -// |MOJO_RESULT_OK| if the watch corresponding to |context| was cancelled. -// |MOJO_RESULT_INVALID_ARGUMENT| if no watch was registered with |context| -// for the given |handle|, or if |handle| is invalid. -MOJO_SYSTEM_EXPORT MojoResult -MojoCancelWatch(MojoHandle handle, uintptr_t context); - // Retrieves system properties. See the documentation for |MojoPropertyType| for // supported property types and their corresponding output value type. //
diff --git a/mojo/public/c/system/thunks.cc b/mojo/public/c/system/thunks.cc index d6bfd95..1e92954 100644 --- a/mojo/public/c/system/thunks.cc +++ b/mojo/public/c/system/thunks.cc
@@ -185,17 +185,33 @@ signals_states); } -MojoResult MojoWatch(MojoHandle handle, - MojoHandleSignals signals, - MojoWatchCallback callback, - uintptr_t context) { - assert(g_thunks.Watch); - return g_thunks.Watch(handle, signals, callback, context); +MojoResult MojoCreateWatcher(MojoWatcherCallback callback, + MojoHandle* watcher_handle) { + assert(g_thunks.CreateWatcher); + return g_thunks.CreateWatcher(callback, watcher_handle); } -MojoResult MojoCancelWatch(MojoHandle handle, uintptr_t context) { +MojoResult MojoWatch(MojoHandle watcher_handle, + MojoHandle handle, + MojoHandleSignals signals, + uintptr_t context) { + assert(g_thunks.Watch); + return g_thunks.Watch(watcher_handle, handle, signals, context); +} + +MojoResult MojoCancelWatch(MojoHandle watcher_handle, uintptr_t context) { assert(g_thunks.CancelWatch); - return g_thunks.CancelWatch(handle, context); + return g_thunks.CancelWatch(watcher_handle, context); +} + +MojoResult MojoArmWatcher(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states) { + assert(g_thunks.ArmWatcher); + return g_thunks.ArmWatcher(watcher_handle, num_ready_contexts, ready_contexts, + ready_results, ready_signals_states); } MojoResult MojoFuseMessagePipes(MojoHandle handle0, MojoHandle handle1) {
diff --git a/mojo/public/c/system/thunks.h b/mojo/public/c/system/thunks.h index 161faf1..31d2289 100644 --- a/mojo/public/c/system/thunks.h +++ b/mojo/public/c/system/thunks.h
@@ -13,28 +13,10 @@ #include "mojo/public/c/system/core.h" #include "mojo/public/c/system/system_export.h" -// The embedder needs to bind the basic Mojo Core functions of a DSO to those of -// the embedder when loading a DSO that is dependent on mojo_system. -// The typical usage would look like: -// base::ScopedNativeLibrary app_library( -// base::LoadNativeLibrary(app_path_, &error)); -// typedef MojoResult (*MojoSetSystemThunksFn)(MojoSystemThunks*); -// MojoSetSystemThunksFn mojo_set_system_thunks_fn = -// reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer( -// "MojoSetSystemThunks")); -// MojoSystemThunks system_thunks = MojoMakeSystemThunks(); -// size_t expected_size = mojo_set_system_thunks_fn(&system_thunks); -// if (expected_size > sizeof(MojoSystemThunks)) { -// LOG(ERROR) -// << "Invalid DSO. Expected MojoSystemThunks size: " -// << expected_size; -// break; -// } - -// Structure used to bind the basic Mojo Core functions of a DSO to those of -// the embedder. -// This is the ABI between the embedder and the DSO. It can only have new -// functions added to the end. No other changes are supported. +// Structure used to bind the basic Mojo Core functions to an embedder +// implementation. This is intended to eventually be used as a stable ABI +// between a Mojo embedder and some loaded application code, but for now it is +// still effectively safe to rearrange entries as needed. #pragma pack(push, 8) struct MojoSystemThunks { size_t size; // Should be set to sizeof(MojoSystemThunks). @@ -115,11 +97,18 @@ MojoHandle* handles, MojoResult* results, struct MojoHandleSignalsState* signals_states); - MojoResult (*Watch)(MojoHandle handle, + MojoResult (*CreateWatcher)(MojoWatcherCallback callback, + MojoHandle* watcher_handle); + MojoResult (*Watch)(MojoHandle watcher_handle, + MojoHandle handle, MojoHandleSignals signals, - MojoWatchCallback callback, uintptr_t context); - MojoResult (*CancelWatch)(MojoHandle handle, uintptr_t context); + MojoResult (*CancelWatch)(MojoHandle watcher_handle, uintptr_t context); + MojoResult (*ArmWatcher)(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + MojoHandleSignalsState* ready_signals_states); MojoResult (*FuseMessagePipes)(MojoHandle handle0, MojoHandle handle1); MojoResult (*WriteMessageNew)(MojoHandle message_pipe_handle, MojoMessageHandle message,
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h index 7e02eeb..967ce15 100644 --- a/mojo/public/c/system/types.h +++ b/mojo/public/c/system/types.h
@@ -189,24 +189,25 @@ MOJO_STATIC_ASSERT(sizeof(MojoHandleSignalsState) == 8, "MojoHandleSignalsState has wrong size"); -// |MojoWatchNotificationFlags|: Passed to a callback invoked as a result of -// signals being raised on a handle watched by |MojoWatch()|. May take the -// following values: -// |MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM| - The callback is being invoked -// as a result of a system-level event rather than a direct API call from -// user code. This may be used as an indication that user code is safe to -// call without fear of reentry. +// |MojoWatcherNotificationFlags|: Passed to a callback invoked by a watcher +// when some observed signals are raised or a watched handle is closed. May take +// on any combination of the following values: +// +// |MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM| - The callback is being +// invoked as a result of a system-level event rather than a direct API +// call from user code. This may be used as an indication that user code +// is safe to call without fear of reentry. -typedef uint32_t MojoWatchNotificationFlags; +typedef uint32_t MojoWatcherNotificationFlags; #ifdef __cplusplus -const MojoWatchNotificationFlags MOJO_WATCH_NOTIFICATION_FLAG_NONE = 0; -const MojoWatchNotificationFlags MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM = +const MojoWatcherNotificationFlags MOJO_WATCHER_NOTIFICATION_FLAG_NONE = 0; +const MojoWatcherNotificationFlags MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM = 1 << 0; #else -#define MOJO_WATCH_NOTIFICATION_FLAG_NONE ((MojoWatchNotificationFlags)0) -#define MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM \ - ((MojoWatchNotificationFlags)1 << 0); +#define MOJO_WATCHER_NOTIFICATION_FLAG_NONE ((MojoWatcherNotificationFlags)0) +#define MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM \ + ((MojoWatcherNotificationFlags)1 << 0); #endif // |MojoPropertyType|: Property types that can be passed to |MojoGetProperty()|
diff --git a/mojo/public/c/system/watcher.h b/mojo/public/c/system/watcher.h new file mode 100644 index 0000000..f152c50 --- /dev/null +++ b/mojo/public/c/system/watcher.h
@@ -0,0 +1,183 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_SYSTEM_WATCHER_H_ +#define MOJO_PUBLIC_C_SYSTEM_WATCHER_H_ + +#include <stdint.h> + +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// A callback used to notify watchers about events on their watched handles. +// +// See documentation for |MojoWatcherNotificationFlags| for details regarding +// the possible values of |flags|. +// +// See documentation for |MojoWatch()| for details regarding the other arguments +// this callback receives when called. +typedef void (*MojoWatcherCallback)(uintptr_t context, + MojoResult result, + struct MojoHandleSignalsState signals_state, + MojoWatcherNotificationFlags flags); + +// Creates a new watcher. +// +// Watchers are used to trigger arbitrary code execution when one or more +// handles change state to meet certain conditions. +// +// A newly registered watcher is initially disarmed and may be armed using +// |MojoArmWatcher()|. A watcher is also always disarmed immediately before any +// invocation of one or more notification callbacks in response to a single +// handle's state changing in some relevant way. +// +// Parameters: +// |callback|: The |MojoWatcherCallback| to invoke any time the watcher is +// notified of an event. See |MojoWatch()| for details regarding arguments +// passed to the callback. Note that this may be called from any arbitrary +// thread. +// |watcher_handle|: The address at which to store the MojoHandle +// corresponding to the new watcher if successfully created. +// +// Returns: +// |MOJO_RESULT_OK| if the watcher has been successfully created. +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if a handle could not be allocated for +// this watcher. +MOJO_SYSTEM_EXPORT MojoResult MojoCreateWatcher(MojoWatcherCallback callback, + MojoHandle* watcher_handle); + +// Adds a watch to a watcher. This allows the watcher to fire notifications +// regarding state changes on the handle corresponding to the arguments given. +// +// Note that notifications for a given watch context are guaranteed to be +// mutually exclusive in execution: the callback will never be entered for a +// given context while another invocation of the callback is still executing for +// the same context. As a result it is generally a good idea to ensure that +// callbacks do as little work as necessary in order to process the +// notification. +// +// Parameters: +// |watcher_handle|: The watcher to which |handle| is to be added. +// |handle|: The handle to add to the watcher. +// |signals|: The signals to watch for on |handle|. +// |context|: An arbitrary context value given to any invocation of the +// watcher's callback when invoked as a result of some state change +// relevant to this combination of |handle| and |signals|. Must be +// unique within any given watcher. +// +// Callback parameters (see |MojoWatcherNotificationCallback| above): +// When the watcher invokes its callback as a result of some notification +// relevant to this watch operation, |context| receives the value given here +// and |signals_state| receives the last known signals state of this handle. +// +// |result| is one of the following: +// |MOJO_RESULT_OK| if at least one of the watched signals is satisfied. The +// watcher must be armed for this notification to fire. +// |MOJO_RESULT_FAILED_PRECONDITION| if all of the watched signals are +// permanently unsatisfiable. The watcher must be armed for this +// notification to fire. +// |MOJO_RESULT_CANCELLED| if the watch has been cancelled. The may occur if +// the watcher has been closed, the watched handle has been closed, or +// the watch for |context| has been explicitly cancelled. This is always +// the last result received for any given context, and it is guaranteed +// to be received exactly once per watch, regardless of how the watch +// was cancelled. +// +// Returns: +// |MOJO_RESULT_OK| if the handle is now being watched by the watcher. +// |MOJO_RESULT_INVALID_ARGUMENT| if |watcher_handle| is not a watcher handle, +// |handle| is not a valid message pipe or data pipe handle. +// |MOJO_RESULT_ALREADY_EXISTS| if the watcher already has a watch registered +// for the given value of |context| or for the given |handle|. +MOJO_SYSTEM_EXPORT MojoResult MojoWatch(MojoHandle watcher_handle, + MojoHandle handle, + MojoHandleSignals signals, + uintptr_t context); + +// Removes a watch from a watcher. +// +// This ensures that the watch is cancelled as soon as possible. Cancellation +// may be deferred (or may even block) an aritrarily long time if the watch is +// already dispatching one or more notifications. +// +// When cancellation is complete, the watcher's callback is invoked one final +// time for |context|, with the result |MOJO_RESULT_CANCELLED|. +// +// The same behavior can be elicted by either closing the watched handle +// associated with this context, or by closing |watcher_handle| itself. In the +// lastter case, all registered contexts on the watcher are implicitly cancelled +// in a similar fashion. +// +// Parameters: +// |watcher_handle|: The handle of the watcher from which to remove a watch. +// |context|: The context of the watch to be removed. +// +// Returns: +// |MOJO_RESULT_OK| if the watch has been cancelled. +// |MOJO_RESULT_INVALID_ARGUMENT| if |watcher_handle| is not a watcher handle. +// |MOJO_RESULT_NOT_FOUND| if there is no watch registered on this watcher for +// the given value of |context|. +MOJO_SYSTEM_EXPORT MojoResult MojoCancelWatch(MojoHandle watcher_handle, + uintptr_t context); + +// Arms a watcher, enabling a single future event on one of the watched handles +// to trigger a single notification for each relevant watch context associated +// with that handle. +// +// Parameters: +// |watcher_handle|: The handle of the watcher. +// |num_ready_contexts|: An address pointing to the number of elements +// available for storage in the remaining output buffers. Optional and +// only used on failure. See |MOJO_RESULT_FAILED_PRECONDITION| below for +// more details. +// |ready_contexts|: An output buffer for contexts corresponding to the +// watches which would have notified if the watcher were armed. Optional +// and only uesd on failure. See |MOJO_RESULT_FAILED_PRECONDITION| below +// for more details. +// |ready_results|: An output buffer for MojoResult values corresponding to +// each context in |ready_contexts|. Optional and only used on failure. +// See |MOJO_RESULT_FAILED_PRECONDITION| below for more details. +// |ready_signals_states|: An output buffer for |MojoHandleSignalsState| +// structures corresponding to each context in |ready_contexts|. Optional +// and only used on failure. See |MOJO_RESULT_FAILED_PRECONDITION| below +// for more details. +// +// Returns: +// |MOJO_RESULT_OK| if the watcher has been successfully armed. All arguments +// other than |watcher_handle| are ignored in this case. +// |MOJO_RESULT_NOT_FOUND| if the watcher does not have any registered watch +// contexts. All arguments other than |watcher_handle| are ignored in this +// case. +// |MOJO_RESULT_INVALID_ARGUMENT| if |watcher_handle| is not a valid watcher +// handle, or if |num_ready_contexts| is non-null but any of the output +// buffer paramters is null. +// |MOJO_RESULT_FAILED_PRECONDITION| if one or more watches would have +// notified immediately upon arming the watcher. If |num_handles| is +// non-null, this assumes there is enough space for |*num_handles| entries +// in each of the subsequent output buffer arguments. +// +// At most that many entries are placed in the output buffers, +// corresponding to the watches which would have signalled if the watcher +// had been armed successfully. The actual number of entries placed in the +// output buffers is written to |*num_ready_contexts| before returning. +// +// If more than (input) |*num_ready_contexts| watch contexts were ready to +// notify, the subset presented in output buffers is arbitrary and +// implementation-defined. +MOJO_SYSTEM_EXPORT MojoResult +MojoArmWatcher(MojoHandle watcher_handle, + uint32_t* num_ready_contexts, + uintptr_t* ready_contexts, + MojoResult* ready_results, + struct MojoHandleSignalsState* ready_signals_states); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_WATCHER_H_
diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h index 1da331b..ba5954c2 100644 --- a/mojo/public/cpp/bindings/binding.h +++ b/mojo/public/cpp/bindings/binding.h
@@ -208,6 +208,10 @@ internal_state_.CloseWithReason(custom_reason, description); } + void EnableNestedDispatch(bool enabled) { + internal_state_.EnableNestedDispatch(enabled); + } + // Unbinds the underlying pipe from this binding and returns it so it can be // used in another context, such as on another thread or with a different // implementation. Put this object into a state where it can be rebound to a
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h index 01e92367..fdfeb73 100644 --- a/mojo/public/cpp/bindings/connector.h +++ b/mojo/public/cpp/bindings/connector.h
@@ -18,7 +18,7 @@ #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/sync_handle_watcher.h" #include "mojo/public/cpp/system/core.h" -#include "mojo/public/cpp/system/watcher.h" +#include "mojo/public/cpp/system/simple_watcher.h" namespace base { class Lock; @@ -155,8 +155,14 @@ // |tag| must be a const string literal. void SetWatcherHeapProfilerTag(const char* tag); + // Enables support for nested message dispatch so that the Connector can + // continue dispatching inbound messages even if one of them spins a nested + // message loop. This should be enabled only when needed, as dispatch in this + // mode is generally less efficient. + void EnableNestedDispatch(bool enabled); + private: - // Callback of mojo::Watcher. + // Callback of mojo::SimpleWatcher. void OnWatcherHandleReady(MojoResult result); // Callback of SyncHandleWatcher. void OnSyncHandleWatcherHandleReady(MojoResult result); @@ -188,7 +194,7 @@ MessageReceiver* incoming_receiver_ = nullptr; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - std::unique_ptr<Watcher> handle_watcher_; + std::unique_ptr<SimpleWatcher> handle_watcher_; bool error_ = false; bool drop_writes_ = false; @@ -196,6 +202,8 @@ bool paused_ = false; + bool nested_dispatch_enabled_ = false; + // If sending messages is allowed from multiple threads, |lock_| is used to // protect modifications to |message_pipe_| and |drop_writes_|. base::Optional<base::Lock> lock_;
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h index e88be74..a56b9dd 100644 --- a/mojo/public/cpp/bindings/interface_ptr.h +++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -193,6 +193,10 @@ return !(*this) && !other; } + void EnableNestedDispatch(bool enabled) { + internal_state_.EnableNestedDispatch(enabled); + } + // DO NOT USE. Exposed only for internal use and for testing. internal::InterfacePtrState<Interface>* internal_state() { return &internal_state_;
diff --git a/mojo/public/cpp/bindings/lib/binding_state.cc b/mojo/public/cpp/bindings/lib/binding_state.cc index b34cb47..85392cd 100644 --- a/mojo/public/cpp/bindings/lib/binding_state.cc +++ b/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -51,6 +51,10 @@ Close(); } +void BindingStateBase::EnableNestedDispatch(bool enabled) { + router_->EnableNestedDispatch(enabled); +} + void BindingStateBase::FlushForTesting() { endpoint_client_->FlushForTesting(); }
diff --git a/mojo/public/cpp/bindings/lib/binding_state.h b/mojo/public/cpp/bindings/lib/binding_state.h index 0b0dbee0..ca7d5a11 100644 --- a/mojo/public/cpp/bindings/lib/binding_state.h +++ b/mojo/public/cpp/bindings/lib/binding_state.h
@@ -68,6 +68,8 @@ return router_->handle(); } + void EnableNestedDispatch(bool enabled); + void FlushForTesting(); void EnableTestingMode();
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index 4426def..ff9867a 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -188,6 +188,12 @@ } } +void Connector::EnableNestedDispatch(bool enabled) { + nested_dispatch_enabled_ = enabled; + handle_watcher_.reset(); + WaitToReadMore(); +} + void Connector::OnWatcherHandleReady(MojoResult result) { OnHandleReadyInternal(result); } @@ -211,6 +217,7 @@ HandleError(result != MOJO_RESULT_FAILED_PRECONDITION, false); return; } + ReadAllAvailableMessages(); // At this point, this object might have been deleted. Return. } @@ -219,10 +226,11 @@ CHECK(!paused_); DCHECK(!handle_watcher_); - handle_watcher_.reset(new Watcher(FROM_HERE, task_runner_)); + handle_watcher_.reset(new SimpleWatcher( + FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL, task_runner_)); if (heap_profiler_tag_) handle_watcher_->set_heap_profiler_tag(heap_profiler_tag_); - MojoResult rv = handle_watcher_->Start( + MojoResult rv = handle_watcher_->Watch( message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&Connector::OnWatcherHandleReady, base::Unretained(this))); @@ -232,6 +240,8 @@ task_runner_->PostTask( FROM_HERE, base::Bind(&Connector::OnWatcherHandleReady, weak_self_, rv)); + } else { + handle_watcher_->ArmOrNotify(); } if (allow_woken_up_by_others_) { @@ -253,6 +263,13 @@ const MojoResult rv = ReadMessage(message_pipe_.get(), &message); *read_result = rv; + if (nested_dispatch_enabled_) { + // When supporting nested dispatch, we have to rearm the Watcher immediately + // after reading each message (i.e. before dispatch) to ensure that the next + // inbound message can trigger OnHandleReady on the nested loop. + handle_watcher_->ArmOrNotify(); + } + if (rv == MOJO_RESULT_OK) { receiver_result = incoming_receiver_ && incoming_receiver_->Accept(&message); @@ -278,19 +295,36 @@ void Connector::ReadAllAvailableMessages() { while (!error_) { + base::WeakPtr<Connector> weak_self = weak_self_; MojoResult rv; - if (!ReadSingleMessage(&rv)) { - // Return immediately without touching any members. |this| may have been - // destroyed. + // May delete |this.| + if (!ReadSingleMessage(&rv)) return; + + if (!weak_self || paused_) + return; + + DCHECK(rv == MOJO_RESULT_OK || rv == MOJO_RESULT_SHOULD_WAIT); + + if (rv == MOJO_RESULT_SHOULD_WAIT) { + // Attempt to re-arm the Watcher. + MojoResult ready_result; + MojoResult arm_result = handle_watcher_->Arm(&ready_result); + if (arm_result == MOJO_RESULT_OK) + return; + + // The watcher is already ready to notify again. + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, arm_result); + + if (ready_result == MOJO_RESULT_FAILED_PRECONDITION) { + HandleError(false, false); + return; + } + + // There's more to read now, so we'll just keep looping. + DCHECK_EQ(MOJO_RESULT_OK, ready_result); } - - if (paused_) - return; - - if (rv == MOJO_RESULT_SHOULD_WAIT) - break; } }
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h index 8f5b4ff..d1cd3e6 100644 --- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h +++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -150,6 +150,11 @@ return endpoint_client_->associated_group(); } + void EnableNestedDispatch(bool enabled) { + ConfigureProxyIfNecessary(); + router_->EnableNestedDispatch(enabled); + } + void EnableTestingMode() { ConfigureProxyIfNecessary(); router_->EnableTestingMode();
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc index 2da459a..40d07887 100644 --- a/mojo/public/cpp/bindings/lib/multiplex_router.cc +++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -605,6 +605,11 @@ return !base::ContainsKey(endpoints_, kMasterInterfaceId); } +void MultiplexRouter::EnableNestedDispatch(bool enabled) { + DCHECK(thread_checker_.CalledOnValidThread()); + connector_.EnableNestedDispatch(enabled); +} + void MultiplexRouter::EnableTestingMode() { DCHECK(thread_checker_.CalledOnValidThread()); MayAutoLock locker(&lock_);
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h index cac138bcb..8f1f793 100644 --- a/mojo/public/cpp/bindings/lib/multiplex_router.h +++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -130,6 +130,8 @@ // Whether there are any associated interfaces running currently. bool HasAssociatedEndpoints() const; + void EnableNestedDispatch(bool enabled); + // Sets this object to testing mode. // In testing mode, the object doesn't disconnect the underlying message pipe // when it receives unexpected or invalid messages.
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc index 74ecb7a..a081d1d095 100644 --- a/mojo/public/cpp/bindings/tests/connector_unittest.cc +++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -568,6 +568,7 @@ run_loop.QuitClosure())); connector1.set_incoming_receiver(&accumulator); + connector1.EnableNestedDispatch(true); run_loop.Run(); ASSERT_EQ(2u, accumulator.size());
diff --git a/mojo/public/cpp/system/BUILD.gn b/mojo/public/cpp/system/BUILD.gn index 0dc7af9d..2fc9075 100644 --- a/mojo/public/cpp/system/BUILD.gn +++ b/mojo/public/cpp/system/BUILD.gn
@@ -33,6 +33,8 @@ "message_pipe.h", "platform_handle.cc", "platform_handle.h", + "simple_watcher.cc", + "simple_watcher.h", "system_export.h", "watcher.cc", "watcher.h",
diff --git a/mojo/public/cpp/system/simple_watcher.cc b/mojo/public/cpp/system/simple_watcher.cc new file mode 100644 index 0000000..218a350f --- /dev/null +++ b/mojo/public/cpp/system/simple_watcher.cc
@@ -0,0 +1,273 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/system/simple_watcher.h" + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" +#include "base/trace_event/heap_profiler.h" +#include "mojo/public/c/system/watcher.h" + +namespace mojo { + +// Thread-safe Context object used to dispatch watch notifications from a +// arbitrary threads. +class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> { + public: + // Creates a |Context| instance for a new watch on |watcher|, to watch + // |handle| for |signals|. + static scoped_refptr<Context> Create( + base::WeakPtr<SimpleWatcher> watcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + WatcherHandle watcher_handle, + Handle handle, + MojoHandleSignals signals, + MojoResult* watch_result) { + scoped_refptr<Context> context = new Context(watcher, task_runner); + + // If MojoWatch succeeds, it assumes ownership of a reference to |context|. + // In that case, this reference is balanced in CallNotify() when |result| is + // |MOJO_RESULT_CANCELLED|. + context->AddRef(); + + *watch_result = MojoWatch(watcher_handle.value(), handle.value(), signals, + context->value()); + if (*watch_result != MOJO_RESULT_OK) { + // Balanced by the AddRef() above since watching failed. + context->Release(); + return nullptr; + } + + return context; + } + + static void CallNotify(uintptr_t context_value, + MojoResult result, + MojoHandleSignalsState signals_state, + MojoWatcherNotificationFlags flags) { + auto* context = reinterpret_cast<Context*>(context_value); + context->Notify(result, signals_state, flags); + + // That was the last notification for the context. We can release the ref + // owned by the watch, which may in turn delete the Context. + if (result == MOJO_RESULT_CANCELLED) + context->Release(); + } + + uintptr_t value() const { return reinterpret_cast<uintptr_t>(this); } + + void DisableCancellationNotifications() { + base::AutoLock lock(lock_); + enable_cancellation_notifications_ = false; + } + + private: + friend class base::RefCountedThreadSafe<Context>; + + Context(base::WeakPtr<SimpleWatcher> weak_watcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : weak_watcher_(weak_watcher), task_runner_(task_runner) {} + ~Context() {} + + void Notify(MojoResult result, + MojoHandleSignalsState signals_state, + MojoWatcherNotificationFlags flags) { + if (result == MOJO_RESULT_CANCELLED) { + // The SimpleWatcher may have explicitly cancelled this watch, so we don't + // bother dispatching the notification - it would be ignored anyway. + // + // TODO(rockot): This shouldn't really be necessary, but there are already + // instances today where bindings object may be bound and subsequently + // closed due to pipe error, all before the thread's TaskRunner has been + // properly initialized. + base::AutoLock lock(lock_); + if (!enable_cancellation_notifications_) + return; + } + + if ((flags & MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM) && + task_runner_->RunsTasksOnCurrentThread() && weak_watcher_ && + weak_watcher_->is_default_task_runner_) { + // System notifications will trigger from the task runner passed to + // mojo::edk::InitIPCSupport(). In Chrome this happens to always be the + // default task runner for the IO thread. + weak_watcher_->OnHandleReady(make_scoped_refptr(this), result); + } else { + task_runner_->PostTask( + FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady, weak_watcher_, + make_scoped_refptr(this), result)); + } + } + + const base::WeakPtr<SimpleWatcher> weak_watcher_; + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + base::Lock lock_; + bool enable_cancellation_notifications_ = true; + + DISALLOW_COPY_AND_ASSIGN(Context); +}; + +SimpleWatcher::SimpleWatcher(const tracked_objects::Location& from_here, + ArmingPolicy arming_policy, + scoped_refptr<base::SingleThreadTaskRunner> runner) + : arming_policy_(arming_policy), + task_runner_(std::move(runner)), + is_default_task_runner_(task_runner_ == + base::ThreadTaskRunnerHandle::Get()), + heap_profiler_tag_(from_here.file_name()), + weak_factory_(this) { + MojoResult rv = CreateWatcher(&Context::CallNotify, &watcher_handle_); + DCHECK_EQ(MOJO_RESULT_OK, rv); + DCHECK(task_runner_->BelongsToCurrentThread()); +} + +SimpleWatcher::~SimpleWatcher() { + if (IsWatching()) + Cancel(); +} + +bool SimpleWatcher::IsWatching() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return context_ != nullptr; +} + +MojoResult SimpleWatcher::Watch(Handle handle, + MojoHandleSignals signals, + const ReadyCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!IsWatching()); + DCHECK(!callback.is_null()); + + callback_ = callback; + handle_ = handle; + + MojoResult watch_result = MOJO_RESULT_UNKNOWN; + context_ = + Context::Create(weak_factory_.GetWeakPtr(), task_runner_, + watcher_handle_.get(), handle_, signals, &watch_result); + if (!context_) { + handle_.set_value(kInvalidHandleValue); + callback_.Reset(); + DCHECK_EQ(MOJO_RESULT_INVALID_ARGUMENT, watch_result); + return watch_result; + } + + if (arming_policy_ == ArmingPolicy::AUTOMATIC) + ArmOrNotify(); + + return MOJO_RESULT_OK; +} + +void SimpleWatcher::Cancel() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // The watcher may have already been cancelled if the handle was closed. + if (!context_) + return; + + // Prevent the cancellation notification from being dispatched to + // OnHandleReady() when cancellation is explicit. See the note in the + // implementation of DisableCancellationNotifications() above. + context_->DisableCancellationNotifications(); + + handle_.set_value(kInvalidHandleValue); + callback_.Reset(); + + // Ensure |context_| is unset by the time we call MojoCancelWatch, as may + // re-enter the notification callback and we want to ensure |context_| is + // unset by then. + scoped_refptr<Context> context; + std::swap(context, context_); + MojoResult rv = + MojoCancelWatch(watcher_handle_.get().value(), context->value()); + + // It's possible this cancellation could race with a handle closure + // notification, in which case the watch may have already been implicitly + // cancelled. + DCHECK(rv == MOJO_RESULT_OK || rv == MOJO_RESULT_NOT_FOUND); +} + +MojoResult SimpleWatcher::Arm(MojoResult* ready_result) { + DCHECK(thread_checker_.CalledOnValidThread()); + uint32_t num_ready_contexts = 1; + uintptr_t ready_context; + MojoResult local_ready_result; + MojoHandleSignalsState ready_state; + MojoResult rv = + MojoArmWatcher(watcher_handle_.get().value(), &num_ready_contexts, + &ready_context, &local_ready_result, &ready_state); + if (rv == MOJO_RESULT_FAILED_PRECONDITION) { + DCHECK(context_); + DCHECK_EQ(1u, num_ready_contexts); + DCHECK_EQ(context_->value(), ready_context); + if (ready_result) + *ready_result = local_ready_result; + } + + return rv; +} + +void SimpleWatcher::ArmOrNotify() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Already cancelled, nothing to do. + if (!IsWatching()) + return; + + MojoResult ready_result; + MojoResult rv = Arm(&ready_result); + if (rv == MOJO_RESULT_OK) + return; + + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); + task_runner_->PostTask(FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady, + weak_factory_.GetWeakPtr(), + context_, ready_result)); +} + +void SimpleWatcher::OnHandleReady(scoped_refptr<const Context> context, + MojoResult result) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // This notification may be for a previously watched context, in which case + // we just ignore it. + if (context != context_) + return; + + ReadyCallback callback = callback_; + if (result == MOJO_RESULT_CANCELLED) { + // Implicit cancellation due to someone closing the watched handle. We clear + // the SimppleWatcher's state before dispatching this. + context_ = nullptr; + handle_.set_value(kInvalidHandleValue); + callback_.Reset(); + } + + // NOTE: It's legal for |callback| to delete |this|. + if (!callback.is_null()) { + TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(heap_profiler_tag_); + + base::WeakPtr<SimpleWatcher> weak_self = weak_factory_.GetWeakPtr(); + callback.Run(result); + if (!weak_self) + return; + + if (unsatisfiable_) + return; + + // Prevent |MOJO_RESULT_FAILED_PRECONDITION| task spam by only notifying + // at most once in AUTOMATIC arming mode. + if (result == MOJO_RESULT_FAILED_PRECONDITION) + unsatisfiable_ = true; + + if (arming_policy_ == ArmingPolicy::AUTOMATIC && IsWatching()) + ArmOrNotify(); + } +} + +} // namespace mojo
diff --git a/mojo/public/cpp/system/simple_watcher.h b/mojo/public/cpp/system/simple_watcher.h new file mode 100644 index 0000000..5e5a7ea3 --- /dev/null +++ b/mojo/public/cpp/system/simple_watcher.h
@@ -0,0 +1,211 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_ + +#include "base/callback.h" +#include "base/location.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" +#include "base/threading/thread_task_runner_handle.h" +#include "mojo/public/c/system/types.h" +#include "mojo/public/cpp/system/system_export.h" +#include "mojo/public/cpp/system/watcher.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace mojo { + +// This provides a convenient thread-bound watcher implementation to safely +// watch a single handle, dispatching state change notifications to an arbitrary +// SingleThreadTaskRunner running on the same thread as the SimpleWatcher. +// +// SimpleWatcher exposes the concept of "arming" from the low-level Watcher API. +// In general, a SimpleWatcher must be "armed" in order to dispatch a single +// notification, and must then be rearmed before it will dispatch another. For +// more details, see the documentation for ArmingPolicy and the Arm() and +// ArmOrNotify() methods below. +class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { + public: + // A callback to be called any time a watched handle changes state in some + // interesting way. The |result| argument indicates one of the following + // conditions depending on its value: + // + // |MOJO_RESULT_OK|: One or more of the signals being watched is satisfied. + // + // |MOJO_RESULT_FAILED_PRECONDITION|: None of the signals being watched can + // ever be satisfied again. + // + // |MOJO_RESULT_CANCELLED|: The watched handle has been closed. No further + // notifications will be fired, as this equivalent to an implicit + // CancelWatch(). + // + // Note that unlike the first two conditions, this callback may be invoked + // with |MOJO_RESULT_CANCELLED| even while the SimpleWatcher is disarmed. + using ReadyCallback = base::Callback<void(MojoResult result)>; + + // Selects how this SimpleWatcher is to be armed. + enum class ArmingPolicy { + // The SimpleWatcher is armed automatically on Watch() and rearmed again + // after every invocation of the ReadyCallback. There is no need to manually + // call Arm() on a SimpleWatcher using this policy. This mode is equivalent + // to calling ArmOrNotify() once after Watch() and once again after every + // dispatched notification in MANUAL mode. + // + // This provides a reasonable approximation of edge-triggered behavior, + // mitigating (but not completely eliminating) the potential for redundant + // notifications. + // + // NOTE: It is important when using AUTOMATIC policy that your ReadyCallback + // always attempt to change the state of the handle (e.g. read available + // messages on a message pipe.) Otherwise this will result in a potentially + // large number of avoidable redundant tasks. + // + // For perfect edge-triggered behavior, use MANUAL policy and manually Arm() + // the SimpleWatcher as soon as it becomes possible to do so again. + AUTOMATIC, + + // The SimpleWatcher is never armed automatically. Arm() or ArmOrNotify() + // must be called manually before any non-cancellation notification can be + // dispatched to the ReadyCallback. See the documentation for Arm() and + // ArmNotify() methods below for more details. + MANUAL, + }; + + SimpleWatcher(const tracked_objects::Location& from_here, + ArmingPolicy arming_policy, + scoped_refptr<base::SingleThreadTaskRunner> runner = + base::ThreadTaskRunnerHandle::Get()); + ~SimpleWatcher(); + + // Indicates if the SimpleWatcher is currently watching a handle. + bool IsWatching() const; + + // Starts watching |handle|. A SimpleWatcher may only watch one handle at a + // time, but it is safe to call this more than once as long as the previous + // watch has been cancelled (i.e. |IsWatching()| returns |false|.) + // + // If |handle| is not a valid watchable (message or data pipe) handle or + // |signals| is not a valid set of signals to watch, this returns + // |MOJO_RESULT_INVALID_ARGUMENT|. + // + // Otherwise |MOJO_RESULT_OK| is returned and the handle will be watched until + // either |handle| is closed, the SimpleWatcher is destroyed, or Cancel() is + // explicitly called. + // + // Once the watch is started, |callback| may be called at any time on the + // current thread until |Cancel()| is called or the handle is closed. Note + // that |callback| can be called for results other than + // |MOJO_RESULT_CANCELLED| only if the SimpleWatcher is currently armed. Use + // ArmingPolicy to configure how a SimpleWatcher is armed. + // + // |MOJO_RESULT_CANCELLED| may be dispatched even while the SimpleWatcher + // is disarmed, and no further notifications will be dispatched after that. + // + // Destroying the SimpleWatcher implicitly calls |Cancel()|. + MojoResult Watch(Handle handle, + MojoHandleSignals signals, + const ReadyCallback& callback); + + // Cancels the current watch. Once this returns, the ReadyCallback previously + // passed to |Watch()| will never be called again for this SimpleWatcher. + // + // Note that when cancelled with an explicit call to |Cancel()| the + // ReadyCallback will not be invoked with a |MOJO_RESULT_CANCELLED| result. + void Cancel(); + + // Manually arms the SimpleWatcher. + // + // Arming the SimpleWatcher allows it to fire a single notification regarding + // some future relevant change in the watched handle's state. It's only valid + // to call Arm() while a handle is being watched (see Watch() above.) + // + // SimpleWatcher is always disarmed immediately before invoking its + // ReadyCallback and must be rearmed again before another notification can + // fire. + // + // If the watched handle already meets the watched signaling conditions - + // i.e., if it would have notified immediately once armed - the SimpleWatcher + // is NOT armed, and this call fails with a return value of + // |MOJO_RESULT_FAILED_PRECONDITION|. In that case, what would have been the + // result code for that immediate notification is instead placed in + // |*ready_result| if |ready_result| is non-null. + // + // If the watcher is successfully armed, this returns |MOJO_RESULT_OK| and + // |ready_result| is ignored. + MojoResult Arm(MojoResult* ready_result = nullptr); + + // Manually arms the SimpleWatcher OR posts a task to invoke the ReadyCallback + // with the ready result of the failed arming attempt. + // + // This is meant as a convenient helper for a common usage of Arm(), and it + // ensures that the ReadyCallback will be invoked asynchronously again as soon + // as the watch's conditions are satisfied, assuming the SimpleWatcher isn't + // cancelled first. + // + // Unlike Arm() above, this can never fail. + void ArmOrNotify(); + + Handle handle() const { return handle_; } + ReadyCallback ready_callback() const { return callback_; } + + // Sets the tag used by the heap profiler. + // |tag| must be a const string literal. + void set_heap_profiler_tag(const char* heap_profiler_tag) { + heap_profiler_tag_ = heap_profiler_tag; + } + + private: + class Context; + + void OnHandleReady(scoped_refptr<const Context> context, MojoResult result); + + base::ThreadChecker thread_checker_; + + // The policy used to determine how this SimpleWatcher is armed. + const ArmingPolicy arming_policy_; + + // The TaskRunner of this SimpleWatcher's owning thread. This field is safe to + // access from any thread. + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // Whether |task_runner_| is the same as base::ThreadTaskRunnerHandle::Get() + // for the thread. + const bool is_default_task_runner_; + + ScopedWatcherHandle watcher_handle_; + + // A thread-safe context object corresponding to the currently active watch, + // if any. + scoped_refptr<Context> context_; + + // Fields below must only be accessed on the SimpleWatcher's owning thread. + + // The handle currently under watch. Not owned. + Handle handle_; + + // The callback to call when the handle is signaled. + ReadyCallback callback_; + + // Tracks if the SimpleWatcher has already notified of unsatisfiability. This + // is used to prevent redundant notifications in AUTOMATIC mode. + bool unsatisfiable_ = false; + + // Tag used to ID memory allocations that originated from notifications in + // this watcher. + const char* heap_profiler_tag_ = nullptr; + + base::WeakPtrFactory<SimpleWatcher> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SimpleWatcher); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_
diff --git a/mojo/public/cpp/system/tests/BUILD.gn b/mojo/public/cpp/system/tests/BUILD.gn index 8f98b92..3c3d410 100644 --- a/mojo/public/cpp/system/tests/BUILD.gn +++ b/mojo/public/cpp/system/tests/BUILD.gn
@@ -7,7 +7,7 @@ sources = [ "core_unittest.cc", - "watcher_unittest.cc", + "simple_watcher_unittest.cc", ] deps = [
diff --git a/mojo/public/cpp/system/tests/simple_watcher_unittest.cc b/mojo/public/cpp/system/tests/simple_watcher_unittest.cc new file mode 100644 index 0000000..795f262 --- /dev/null +++ b/mojo/public/cpp/system/tests/simple_watcher_unittest.cc
@@ -0,0 +1,277 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/system/simple_watcher.h" + +#include <memory> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" +#include "mojo/public/c/system/types.h" +#include "mojo/public/cpp/system/message_pipe.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace { + +template <typename Handler> +void RunResultHandler(Handler f, MojoResult result) { + f(result); +} + +template <typename Handler> +SimpleWatcher::ReadyCallback OnReady(Handler f) { + return base::Bind(&RunResultHandler<Handler>, f); +} + +SimpleWatcher::ReadyCallback NotReached() { + return OnReady([](MojoResult) { NOTREACHED(); }); +} + +class SimpleWatcherTest : public testing::Test { + public: + SimpleWatcherTest() {} + ~SimpleWatcherTest() override {} + + private: + base::MessageLoop message_loop_; + + DISALLOW_COPY_AND_ASSIGN(SimpleWatcherTest); +}; + +TEST_F(SimpleWatcherTest, WatchBasic) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + bool notified = false; + base::RunLoop run_loop; + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, + OnReady([&](MojoResult result) { + EXPECT_EQ(MOJO_RESULT_OK, result); + notified = true; + run_loop.Quit(); + }))); + EXPECT_TRUE(b_watcher.IsWatching()); + + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + run_loop.Run(); + EXPECT_TRUE(notified); + + b_watcher.Cancel(); +} + +TEST_F(SimpleWatcherTest, WatchUnsatisfiable) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + a.reset(); + + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL); + EXPECT_EQ( + MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached())); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, b_watcher.Arm()); +} + +TEST_F(SimpleWatcherTest, WatchInvalidHandle) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + a.reset(); + b.reset(); + + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached())); + EXPECT_FALSE(b_watcher.IsWatching()); +} + +TEST_F(SimpleWatcherTest, Cancel) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + base::RunLoop run_loop; + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ( + MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached())); + EXPECT_TRUE(b_watcher.IsWatching()); + b_watcher.Cancel(); + EXPECT_FALSE(b_watcher.IsWatching()); + + // This should never trigger the watcher. + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); +} + +TEST_F(SimpleWatcherTest, CancelOnClose) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + base::RunLoop run_loop; + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, + OnReady([&](MojoResult result) { + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + run_loop.Quit(); + }))); + EXPECT_TRUE(b_watcher.IsWatching()); + + // This should trigger the watcher above. + b.reset(); + + run_loop.Run(); + + EXPECT_FALSE(b_watcher.IsWatching()); +} + +TEST_F(SimpleWatcherTest, CancelOnDestruction) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + base::RunLoop run_loop; + { + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ( + MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, NotReached())); + EXPECT_TRUE(b_watcher.IsWatching()); + + // |b_watcher| should be cancelled when it goes out of scope. + } + + // This should never trigger the watcher above. + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); +} + +TEST_F(SimpleWatcherTest, CloseAndCancel) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, + OnReady([](MojoResult result) { FAIL(); }))); + EXPECT_TRUE(b_watcher.IsWatching()); + + // This should trigger the watcher above... + b.reset(); + // ...but the watcher is cancelled first. + b_watcher.Cancel(); + + EXPECT_FALSE(b_watcher.IsWatching()); + + base::RunLoop().RunUntilIdle(); +} + +TEST_F(SimpleWatcherTest, UnarmedCancel) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL); + base::RunLoop loop; + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, + base::Bind( + [](base::RunLoop* loop, MojoResult result) { + EXPECT_EQ(result, MOJO_RESULT_CANCELLED); + loop->Quit(); + }, + &loop))); + + // This message write will not wake up the watcher since the watcher isn't + // armed. Instead, the cancellation will dispatch due to the reset below. + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + b.reset(); + loop.Run(); +} + +TEST_F(SimpleWatcherTest, ManualArming) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + SimpleWatcher b_watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL); + base::RunLoop loop; + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher.Watch(b.get(), MOJO_HANDLE_SIGNAL_READABLE, + base::Bind( + [](base::RunLoop* loop, MojoResult result) { + EXPECT_EQ(result, MOJO_RESULT_OK); + loop->Quit(); + }, + &loop))); + EXPECT_EQ(MOJO_RESULT_OK, b_watcher.Arm()); + + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + loop.Run(); +} + +TEST_F(SimpleWatcherTest, ManualArmOrNotifyWhileSignaled) { + ScopedMessagePipeHandle a, b; + CreateMessagePipe(nullptr, &a, &b); + + base::RunLoop loop1; + SimpleWatcher b_watcher1(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL); + bool notified1 = false; + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher1.Watch( + b.get(), MOJO_HANDLE_SIGNAL_READABLE, + base::Bind( + [](base::RunLoop* loop, bool* notified, MojoResult result) { + EXPECT_EQ(result, MOJO_RESULT_OK); + *notified = true; + loop->Quit(); + }, + &loop1, ¬ified1))); + + base::RunLoop loop2; + SimpleWatcher b_watcher2(FROM_HERE, SimpleWatcher::ArmingPolicy::MANUAL); + bool notified2 = false; + EXPECT_EQ(MOJO_RESULT_OK, + b_watcher2.Watch( + b.get(), MOJO_HANDLE_SIGNAL_READABLE, + base::Bind( + [](base::RunLoop* loop, bool* notified, MojoResult result) { + EXPECT_EQ(result, MOJO_RESULT_OK); + *notified = true; + loop->Quit(); + }, + &loop2, ¬ified2))); + + // First ensure that |b| is readable. + EXPECT_EQ(MOJO_RESULT_OK, b_watcher1.Arm()); + EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); + loop1.Run(); + + EXPECT_TRUE(notified1); + EXPECT_FALSE(notified2); + notified1 = false; + + // Now verify that ArmOrNotify results in a notification. + b_watcher2.ArmOrNotify(); + loop2.Run(); + + EXPECT_FALSE(notified1); + EXPECT_TRUE(notified2); +} + +} // namespace +} // namespace mojo
diff --git a/mojo/public/cpp/system/tests/watcher_unittest.cc b/mojo/public/cpp/system/tests/watcher_unittest.cc deleted file mode 100644 index 9b59240..0000000 --- a/mojo/public/cpp/system/tests/watcher_unittest.cc +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/system/watcher.h" - -#include <memory> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread_task_runner_handle.h" -#include "mojo/public/c/system/types.h" -#include "mojo/public/cpp/system/message_pipe.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace { - -template <typename Handler> -void RunResultHandler(Handler f, MojoResult result) { f(result); } - -template <typename Handler> -Watcher::ReadyCallback OnReady(Handler f) { - return base::Bind(&RunResultHandler<Handler>, f); -} - -Watcher::ReadyCallback NotReached() { - return OnReady([] (MojoResult) { NOTREACHED(); }); -} - -class WatcherTest : public testing::Test { - public: - WatcherTest() {} - ~WatcherTest() override {} - - private: - base::MessageLoop message_loop_; - - DISALLOW_COPY_AND_ASSIGN(WatcherTest); -}; - -TEST_F(WatcherTest, WatchBasic) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - - bool notified = false; - base::RunLoop run_loop; - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_OK, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - OnReady([&] (MojoResult result) { - EXPECT_EQ(MOJO_RESULT_OK, result); - notified = true; - run_loop.Quit(); - }))); - EXPECT_TRUE(b_watcher.IsWatching()); - - EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE)); - run_loop.Run(); - EXPECT_TRUE(notified); - - b_watcher.Cancel(); -} - -TEST_F(WatcherTest, WatchUnsatisfiable) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - a.reset(); - - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - NotReached())); - EXPECT_FALSE(b_watcher.IsWatching()); -} - -TEST_F(WatcherTest, WatchInvalidHandle) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - a.reset(); - b.reset(); - - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - NotReached())); - EXPECT_FALSE(b_watcher.IsWatching()); -} - -TEST_F(WatcherTest, Cancel) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - - base::RunLoop run_loop; - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_OK, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - NotReached())); - EXPECT_TRUE(b_watcher.IsWatching()); - b_watcher.Cancel(); - EXPECT_FALSE(b_watcher.IsWatching()); - - // This should never trigger the watcher. - EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, run_loop.QuitClosure()); - run_loop.Run(); -} - -TEST_F(WatcherTest, CancelOnClose) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - - base::RunLoop run_loop; - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_OK, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - OnReady([&] (MojoResult result) { - EXPECT_EQ(MOJO_RESULT_CANCELLED, result); - run_loop.Quit(); - }))); - EXPECT_TRUE(b_watcher.IsWatching()); - - // This should trigger the watcher above. - b.reset(); - - run_loop.Run(); - - EXPECT_FALSE(b_watcher.IsWatching()); -} - -TEST_F(WatcherTest, CancelOnDestruction) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - base::RunLoop run_loop; - { - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_OK, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - NotReached())); - EXPECT_TRUE(b_watcher.IsWatching()); - - // |b_watcher| should be cancelled when it goes out of scope. - } - - // This should never trigger the watcher above. - EXPECT_EQ(MOJO_RESULT_OK, WriteMessageRaw(a.get(), "hello", 5, nullptr, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE)); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, run_loop.QuitClosure()); - run_loop.Run(); -} - -TEST_F(WatcherTest, CloseAndCancel) { - ScopedMessagePipeHandle a, b; - CreateMessagePipe(nullptr, &a, &b); - - Watcher b_watcher(FROM_HERE); - EXPECT_EQ(MOJO_RESULT_OK, - b_watcher.Start(b.get(), MOJO_HANDLE_SIGNAL_READABLE, - OnReady([](MojoResult result) { FAIL(); }))); - EXPECT_TRUE(b_watcher.IsWatching()); - - // This should trigger the watcher above... - b.reset(); - // ...but the watcher is cancelled first. - b_watcher.Cancel(); - - EXPECT_FALSE(b_watcher.IsWatching()); - - base::RunLoop().RunUntilIdle(); -} - -} // namespace -} // namespace mojo
diff --git a/mojo/public/cpp/system/watcher.cc b/mojo/public/cpp/system/watcher.cc index 55dcf40..0c62ba8 100644 --- a/mojo/public/cpp/system/watcher.cc +++ b/mojo/public/cpp/system/watcher.cc
@@ -4,114 +4,17 @@ #include "mojo/public/cpp/system/watcher.h" -#include "base/bind.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/trace_event/heap_profiler.h" #include "mojo/public/c/system/functions.h" namespace mojo { -Watcher::Watcher(const tracked_objects::Location& from_here, - scoped_refptr<base::SingleThreadTaskRunner> runner) - : task_runner_(std::move(runner)), - is_default_task_runner_(task_runner_ == - base::ThreadTaskRunnerHandle::Get()), - heap_profiler_tag_(from_here.file_name()), - weak_factory_(this) { - DCHECK(task_runner_->BelongsToCurrentThread()); - weak_self_ = weak_factory_.GetWeakPtr(); -} - -Watcher::~Watcher() { - if(IsWatching()) - Cancel(); -} - -bool Watcher::IsWatching() const { - DCHECK(thread_checker_.CalledOnValidThread()); - return handle_.is_valid(); -} - -MojoResult Watcher::Start(Handle handle, - MojoHandleSignals signals, - const ReadyCallback& callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!IsWatching()); - DCHECK(!callback.is_null()); - - callback_ = callback; - handle_ = handle; - MojoResult result = MojoWatch(handle_.value(), signals, - &Watcher::CallOnHandleReady, - reinterpret_cast<uintptr_t>(this)); - if (result != MOJO_RESULT_OK) { - handle_.set_value(kInvalidHandleValue); - callback_.Reset(); - DCHECK(result == MOJO_RESULT_FAILED_PRECONDITION || - result == MOJO_RESULT_INVALID_ARGUMENT); - return result; - } - - return MOJO_RESULT_OK; -} - -void Watcher::Cancel() { - DCHECK(thread_checker_.CalledOnValidThread()); - - // The watch may have already been cancelled if the handle was closed. - if (!handle_.is_valid()) - return; - - MojoResult result = - MojoCancelWatch(handle_.value(), reinterpret_cast<uintptr_t>(this)); - // |result| may be MOJO_RESULT_INVALID_ARGUMENT if |handle_| has closed, but - // OnHandleReady has not yet been called. - DCHECK(result == MOJO_RESULT_INVALID_ARGUMENT || result == MOJO_RESULT_OK); - handle_.set_value(kInvalidHandleValue); - callback_.Reset(); -} - -void Watcher::OnHandleReady(MojoResult result) { - DCHECK(thread_checker_.CalledOnValidThread()); - - ReadyCallback callback = callback_; - if (result == MOJO_RESULT_CANCELLED) { - handle_.set_value(kInvalidHandleValue); - callback_.Reset(); - } - - // NOTE: It's legal for |callback| to delete |this|. - if (!callback.is_null()) { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(heap_profiler_tag_); - callback.Run(result); - } -} - -// static -void Watcher::CallOnHandleReady(uintptr_t context, - MojoResult result, - MojoHandleSignalsState signals_state, - MojoWatchNotificationFlags flags) { - // NOTE: It is safe to assume the Watcher still exists because this callback - // will never be run after the Watcher's destructor. - // - // TODO: Maybe we should also expose |signals_state| through the Watcher API. - // Current HandleWatcher users have no need for it, so it's omitted here. - Watcher* watcher = reinterpret_cast<Watcher*>(context); - - if ((flags & MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM) && - watcher->task_runner_->RunsTasksOnCurrentThread() && - watcher->is_default_task_runner_) { - // System notifications will trigger from the task runner passed to - // mojo::edk::InitIPCSupport(). In Chrome this happens to always be the - // default task runner for the IO thread. - watcher->OnHandleReady(result); - } else { - watcher->task_runner_->PostTask( - FROM_HERE, - base::Bind(&Watcher::OnHandleReady, watcher->weak_self_, result)); - } +MojoResult CreateWatcher(MojoWatcherCallback callback, + ScopedWatcherHandle* watcher_handle) { + MojoHandle handle; + MojoResult rv = MojoCreateWatcher(callback, &handle); + if (rv == MOJO_RESULT_OK) + watcher_handle->reset(WatcherHandle(handle)); + return rv; } } // namespace mojo
diff --git a/mojo/public/cpp/system/watcher.h b/mojo/public/cpp/system/watcher.h index 236788b..d0a2578 100644 --- a/mojo/public/cpp/system/watcher.h +++ b/mojo/public/cpp/system/watcher.h
@@ -5,121 +5,33 @@ #ifndef MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_ #define MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_ -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_checker.h" -#include "base/threading/thread_task_runner_handle.h" #include "mojo/public/c/system/types.h" +#include "mojo/public/c/system/watcher.h" #include "mojo/public/cpp/system/handle.h" #include "mojo/public/cpp/system/system_export.h" namespace mojo { -// A Watcher watches a single Mojo handle for signal state changes. -// -// NOTE: Watchers may only be used on threads which have a running MessageLoop. -class MOJO_CPP_SYSTEM_EXPORT Watcher { +// A strongly-typed representation of a |MojoHandle| for a watcher. +class WatcherHandle : public Handle { public: - // A callback to be called any time a watched handle changes state in some - // interesting way. The |result| argument indicates one of the following - // conditions depending on its value: - // - // |MOJO_RESULT_OK|: One or more of the signals being watched is satisfied. - // - // |MOJO_RESULT_FAILED_PRECONDITION|: None of the signals being watched can - // ever be satisfied again. - // - // |MOJO_RESULT_CANCELLED|: The handle has been closed and the watch has - // been cancelled implicitly. - using ReadyCallback = base::Callback<void(MojoResult result)>; + WatcherHandle() = default; + explicit WatcherHandle(MojoHandle value) : Handle(value) {} - Watcher(const tracked_objects::Location& from_here, - scoped_refptr<base::SingleThreadTaskRunner> runner = - base::ThreadTaskRunnerHandle::Get()); - - // NOTE: This destructor automatically calls |Cancel()| if the Watcher is - // still active. - ~Watcher(); - - // Indicates if the Watcher is currently watching a handle. - bool IsWatching() const; - - // Starts watching |handle|. A Watcher may only watch one handle at a time, - // but it is safe to call this more than once as long as the previous watch - // has been cancelled (i.e. |is_watching()| returns |false|.) - // - // If no signals in |signals| can ever be satisfied for |handle|, this returns - // |MOJO_RESULT_FAILED_PRECONDITION|. - // - // If |handle| is not a valid watchable (message or data pipe) handle, this - // returns |MOJO_RESULT_INVALID_ARGUMENT|. - // - // Otherwise |MOJO_RESULT_OK| is returned and the handle will be watched until - // closure or cancellation. - // - // Once the watch is started, |callback| may be called at any time on the - // current thread until |Cancel()| is called or the handle is closed. - // - // Destroying the Watcher implicitly calls |Cancel()|. - MojoResult Start(Handle handle, - MojoHandleSignals signals, - const ReadyCallback& callback); - - // Cancels the current watch. Once this returns, the callback previously - // passed to |Start()| will never be called again for this Watcher. - void Cancel(); - - Handle handle() const { return handle_; } - ReadyCallback ready_callback() const { return callback_; } - - // Sets the tag used by the heap profiler. - // |tag| must be a const string literal. - void set_heap_profiler_tag(const char* heap_profiler_tag) { - heap_profiler_tag_ = heap_profiler_tag; - } - - private: - void OnHandleReady(MojoResult result); - - static void CallOnHandleReady(uintptr_t context, - MojoResult result, - MojoHandleSignalsState signals_state, - MojoWatchNotificationFlags flags); - - base::ThreadChecker thread_checker_; - - // The TaskRunner of this Watcher's owning thread. This field is safe to - // access from any thread. - const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - // Whether |task_runner_| is the same as base::ThreadTaskRunnerHandle::Get() - // for the thread. - const bool is_default_task_runner_; - - // A persistent weak reference to this Watcher which can be passed to the - // Dispatcher any time this object should be signalled. Safe to access (but - // not to dereference!) from any thread. - base::WeakPtr<Watcher> weak_self_; - - // Fields below must only be accessed on the Watcher's owning thread. - - // The handle currently under watch. Not owned. - Handle handle_; - - // The callback to call when the handle is signaled. - ReadyCallback callback_; - - // Tag used to ID memory allocations that originated from notifications in - // this watcher. - const char* heap_profiler_tag_ = nullptr; - - base::WeakPtrFactory<Watcher> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(Watcher); + // Copying and assignment allowed. }; +static_assert(sizeof(WatcherHandle) == sizeof(Handle), + "Bad size for C++ WatcherHandle"); + +typedef ScopedHandleBase<WatcherHandle> ScopedWatcherHandle; +static_assert(sizeof(ScopedWatcherHandle) == sizeof(WatcherHandle), + "Bad size for C++ ScopedWatcherHandle"); + +MOJO_CPP_SYSTEM_EXPORT MojoResult +CreateWatcher(MojoWatcherCallback callback, + ScopedWatcherHandle* watcher_handle); + } // namespace mojo #endif // MOJO_PUBLIC_CPP_SYSTEM_WATCHER_H_
diff --git a/net/BUILD.gn b/net/BUILD.gn index 091518f..2cf5735b 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -5108,7 +5108,6 @@ "cookies/cookie_monster_perftest.cc", "disk_cache/disk_cache_perftest.cc", "extras/sqlite/sqlite_persistent_cookie_store_perftest.cc", - "proxy/proxy_resolver_perftest.cc", "socket/udp_socket_perftest.cc", ] @@ -5131,12 +5130,6 @@ sources += [ "websockets/websocket_frame_perftest.cc" ] } - if (use_v8_in_net) { - deps += [ ":net_with_v8" ] - } else { - sources -= [ "proxy/proxy_resolver_perftest.cc" ] - } - # Some linker failures have been observed for this target on the Win64 # continuous builder, see crbug.com/659369. # TODO(sebmarchand): Remove this once we have some data.
diff --git a/net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java b/net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java index 9f840a2f..d398947 100644 --- a/net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java +++ b/net/android/java/src/org/chromium/net/RegistrationPolicyAlwaysRegister.java
@@ -15,5 +15,6 @@ register(); } + @Override protected void destroy() {} }
diff --git a/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java b/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java index 140d478c..7a5c5006 100644 --- a/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java +++ b/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java
@@ -23,6 +23,7 @@ onApplicationStateChange(getApplicationState()); } + @Override protected void destroy() { if (mDestroyed) return; ApplicationStatus.unregisterApplicationStateListener(this);
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc index f5e258e..b209a5a 100644 --- a/net/http/http_proxy_client_socket_wrapper.cc +++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -424,7 +424,9 @@ if (tunnel_) { SpdySessionKey key(GetDestination().host_port_pair(), ProxyServer::Direct(), PRIVACY_MODE_DISABLED); - if (spdy_session_pool_->FindAvailableSession(key, GURL(), net_log_)) { + if (spdy_session_pool_->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, net_log_)) { using_spdy_ = true; next_state_ = STATE_SPDY_PROXY_CREATE_STREAM; return OK; @@ -522,7 +524,9 @@ SpdySessionKey key(GetDestination().host_port_pair(), ProxyServer::Direct(), PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> spdy_session = - spdy_session_pool_->FindAvailableSession(key, GURL(), net_log_); + spdy_session_pool_->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, net_log_); // It's possible that a session to the proxy has recently been created if (spdy_session) { if (transport_socket_handle_.get()) {
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index c837f75..d50d24f 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -541,8 +541,9 @@ // It is OK to dereference spdy_session_pool, because the // ClientSocketPoolManager will be destroyed in the same callback that // destroys the SpdySessionPool. - return spdy_session_pool->FindAvailableSession(spdy_session_key, origin_url, - net_log) + return spdy_session_pool->FindAvailableSession( + spdy_session_key, origin_url, /* enable_ip_based_pooling = */ true, + net_log) ? ERR_SPDY_SESSION_ALREADY_EXISTS : OK; } @@ -952,7 +953,8 @@ if (CanUseExistingSpdySession()) { base::WeakPtr<SpdySession> spdy_session = session_->spdy_session_pool()->FindAvailableSession( - spdy_session_key, origin_url_, net_log_); + spdy_session_key, origin_url_, /* enable_ip_based_pooling = */ true, + net_log_); if (spdy_session) { // If we're preconnecting, but we already have a SpdySession, we don't // actually need to preconnect any sockets, so we're done. @@ -1034,7 +1036,8 @@ SpdySessionKey spdy_session_key = GetSpdySessionKey(); existing_spdy_session_ = session_->spdy_session_pool()->FindAvailableSession( - spdy_session_key, origin_url_, net_log_); + spdy_session_key, origin_url_, + /* enable_ip_based_pooling = */ true, net_log_); if (existing_spdy_session_) { using_spdy_ = true; next_state_ = STATE_CREATE_STREAM; @@ -1246,7 +1249,8 @@ if (!existing_spdy_session_) { existing_spdy_session_ = session_->spdy_session_pool()->FindAvailableSession( - spdy_session_key, origin_url_, net_log_); + spdy_session_key, origin_url_, + /* enable_ip_based_pooling = */ true, net_log_); } bool direct = !IsHttpsProxyAndHttpUrl(); if (existing_spdy_session_.get()) {
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc index 8bd94fb..ded5447 100644 --- a/net/nqe/network_quality_estimator.cc +++ b/net/nqe/network_quality_estimator.cc
@@ -1834,4 +1834,20 @@ return ""; } +base::Optional<base::TimeDelta> +NetworkQualityEstimator::NetworkQualityProvider::GetHttpRTT() const { + return base::Optional<base::TimeDelta>(); +} + +base::Optional<base::TimeDelta> +NetworkQualityEstimator::NetworkQualityProvider::GetTransportRTT() const { + return base::Optional<base::TimeDelta>(); +} + +base::Optional<int32_t> +NetworkQualityEstimator::NetworkQualityProvider::GetDownstreamThroughputKbps() + const { + return base::Optional<int32_t>(); +} + } // namespace net
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h index d44c1a55..5c2718a 100644 --- a/net/nqe/network_quality_estimator.h +++ b/net/nqe/network_quality_estimator.h
@@ -157,11 +157,11 @@ // Provides simple interface to obtain the effective connection type. class NET_EXPORT NetworkQualityProvider { public: + virtual ~NetworkQualityProvider() {} + // Returns the current effective connection type. virtual EffectiveConnectionType GetEffectiveConnectionType() const = 0; - virtual ~NetworkQualityProvider() {} - // Adds |observer| to a list of effective connection type observers. virtual void AddEffectiveConnectionTypeObserver( EffectiveConnectionTypeObserver* observer) = 0; @@ -170,6 +170,19 @@ virtual void RemoveEffectiveConnectionTypeObserver( EffectiveConnectionTypeObserver* observer) = 0; + // Returns the current HTTP RTT estimate. If the estimate is unavailable, + // the returned optional value is null. + virtual base::Optional<base::TimeDelta> GetHttpRTT() const; + + // Returns the current transport RTT estimate. If the estimate is + // unavailable, the returned optional value is null. + virtual base::Optional<base::TimeDelta> GetTransportRTT() const; + + // Returns the current downstream throughput estimate (in kilobits per + // second). If the estimate is unavailable, the returned optional value is + // null. + virtual base::Optional<int32_t> GetDownstreamThroughputKbps() const; + // Adds |observer| to the list of RTT and throughput estimate observers. // |observer| would be notified of the current RTT and throughput estimates // in the next message pump.
diff --git a/net/proxy/proxy_resolver_perftest.cc b/net/proxy/proxy_resolver_perftest.cc deleted file mode 100644 index a910d45..0000000 --- a/net/proxy/proxy_resolver_perftest.cc +++ /dev/null
@@ -1,286 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <utility> - -#include "base/base_paths.h" -#include "base/compiler_specific.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/test/perf_time_logger.h" -#include "net/base/net_errors.h" -#include "net/dns/mock_host_resolver.h" -#include "net/log/net_log_with_source.h" -#include "net/proxy/proxy_info.h" -#include "net/proxy/proxy_resolver.h" -#include "net/proxy/proxy_resolver_factory.h" -#include "net/proxy/proxy_resolver_v8.h" -#include "net/test/embedded_test_server/embedded_test_server.h" -#include "net/test/gtest_util.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "net/proxy/proxy_resolver_winhttp.h" -#elif defined(OS_MACOSX) -#include "net/proxy/proxy_resolver_mac.h" -#endif - -using net::test::IsOk; - -namespace net { - -namespace { - -// This class holds the URL to use for resolving, and the expected result. -// We track the expected result in order to make sure the performance -// test is actually resolving URLs properly, otherwise the perf numbers -// are meaningless :-) -struct PacQuery { - const char* query_url; - const char* expected_result; -}; - -// Entry listing which PAC scripts to load, and which URLs to try resolving. -// |queries| should be terminated by {NULL, NULL}. A sentinel is used -// rather than a length, to simplify using initializer lists. -struct PacPerfTest { - const char* pac_name; - PacQuery queries[100]; - - // Returns the actual number of entries in |queries| (assumes NULL sentinel). - int NumQueries() const; -}; - -// List of performance tests. -static PacPerfTest kPerfTests[] = { - // This test uses an ad-blocker PAC script. This script is very heavily - // regular expression oriented, and has no dependencies on the current - // IP address, or DNS resolving of hosts. - { "no-ads.pac", - { // queries: - {"http://www.google.com", "DIRECT"}, - {"http://www.imdb.com/photos/cmsicons/x", "PROXY 0.0.0.0:3421"}, - {"http://www.imdb.com/x", "DIRECT"}, - {"http://www.staples.com/", "DIRECT"}, - {"http://www.staples.com/pixeltracker/x", "PROXY 0.0.0.0:3421"}, - {"http://www.staples.com/pixel/x", "DIRECT"}, - {"http://www.foobar.com", "DIRECT"}, - {"http://www.foobarbaz.com/x/y/z", "DIRECT"}, - {"http://www.testurl1.com/index.html", "DIRECT"}, - {"http://www.testurl2.com", "DIRECT"}, - {"https://www.sample/pirate/arrrrrr", "DIRECT"}, - {NULL, NULL} - }, - }, -}; - -int PacPerfTest::NumQueries() const { - for (size_t i = 0; i < arraysize(queries); ++i) { - if (queries[i].query_url == NULL) - return i; - } - NOTREACHED(); // Bad definition. - return 0; -} - -// The number of URLs to resolve when testing a PAC script. -const int kNumIterations = 500; - -// Helper class to run through all the performance tests using the specified -// proxy resolver implementation. -class PacPerfSuiteRunner { - public: - // |resolver_name| is the label used when logging the results. - PacPerfSuiteRunner(ProxyResolverFactory* factory, - const std::string& resolver_name) - : factory_(factory), resolver_name_(resolver_name) { - test_server_.ServeFilesFromSourceDirectory( - "net/data/proxy_resolver_perftest"); - } - - void RunAllTests() { - ASSERT_TRUE(test_server_.Start()); - for (size_t i = 0; i < arraysize(kPerfTests); ++i) { - const PacPerfTest& test_data = kPerfTests[i]; - RunTest(test_data.pac_name, - test_data.queries, - test_data.NumQueries()); - } - } - - private: - void RunTest(const std::string& script_name, - const PacQuery* queries, - int queries_len) { - std::unique_ptr<ProxyResolver> resolver; - if (!factory_->expects_pac_bytes()) { - GURL pac_url = test_server_.GetURL(std::string("/") + script_name); - int rv = factory_->CreateProxyResolver( - ProxyResolverScriptData::FromURL(pac_url), &resolver, - CompletionCallback(), nullptr); - EXPECT_THAT(rv, IsOk()); - } else { - resolver = LoadPacScriptAndCreateResolver(script_name); - } - ASSERT_TRUE(resolver); - - // Do a query to warm things up. In the case of internal-fetch proxy - // resolvers, the first resolve will be slow since it has to download - // the PAC script. - { - ProxyInfo proxy_info; - int result = resolver->GetProxyForURL(GURL("http://www.warmup.com"), - &proxy_info, CompletionCallback(), - NULL, NetLogWithSource()); - ASSERT_THAT(result, IsOk()); - } - - // Start the perf timer. - std::string perf_test_name = resolver_name_ + "_" + script_name; - base::PerfTimeLogger timer(perf_test_name.c_str()); - - for (int i = 0; i < kNumIterations; ++i) { - // Round-robin between URLs to resolve. - const PacQuery& query = queries[i % queries_len]; - - // Resolve. - ProxyInfo proxy_info; - int result = resolver->GetProxyForURL(GURL(query.query_url), &proxy_info, - CompletionCallback(), NULL, - NetLogWithSource()); - - // Check that the result was correct. Note that ToPacString() and - // ASSERT_EQ() are fast, so they won't skew the results. - ASSERT_THAT(result, IsOk()); - ASSERT_EQ(query.expected_result, proxy_info.ToPacString()); - } - - // Print how long the test ran for. - timer.Done(); - } - - // Read the PAC script from disk and initialize the proxy resolver with it. - std::unique_ptr<ProxyResolver> LoadPacScriptAndCreateResolver( - const std::string& script_name) { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.AppendASCII("net"); - path = path.AppendASCII("data"); - path = path.AppendASCII("proxy_resolver_perftest"); - path = path.AppendASCII(script_name); - - // Try to read the file from disk. - std::string file_contents; - bool ok = base::ReadFileToString(path, &file_contents); - - // If we can't load the file from disk, something is misconfigured. - LOG_IF(ERROR, !ok) << "Failed to read file: " << path.value(); - if (!ok) - return nullptr; - - // Load the PAC script into the ProxyResolver. - std::unique_ptr<ProxyResolver> resolver; - int rv = factory_->CreateProxyResolver( - ProxyResolverScriptData::FromUTF8(file_contents), &resolver, - CompletionCallback(), nullptr); - EXPECT_THAT(rv, IsOk()); - return resolver; - } - - ProxyResolverFactory* factory_; - std::string resolver_name_; - EmbeddedTestServer test_server_; -}; - -#if defined(OS_WIN) -TEST(ProxyResolverPerfTest, ProxyResolverWinHttp) { - ProxyResolverFactoryWinHttp factory; - PacPerfSuiteRunner runner(&factory, "ProxyResolverWinHttp"); - runner.RunAllTests(); -} -#elif defined(OS_MACOSX) -TEST(ProxyResolverPerfTest, ProxyResolverMac) { - ProxyResolverFactoryMac factory; - PacPerfSuiteRunner runner(&factory, "ProxyResolverMac"); - runner.RunAllTests(); -} -#endif - -class MockJSBindings : public ProxyResolverV8::JSBindings { - public: - MockJSBindings() {} - - void Alert(const base::string16& message) override { CHECK(false); } - - bool ResolveDns(const std::string& host, - ResolveDnsOperation op, - std::string* output, - bool* terminate) override { - CHECK(false); - return false; - } - - void OnError(int line_number, const base::string16& message) override { - CHECK(false); - } -}; - -class ProxyResolverV8Wrapper : public ProxyResolver { - public: - ProxyResolverV8Wrapper(std::unique_ptr<ProxyResolverV8> resolver, - std::unique_ptr<MockJSBindings> bindings) - : resolver_(std::move(resolver)), bindings_(std::move(bindings)) {} - - int GetProxyForURL(const GURL& url, - ProxyInfo* results, - const CompletionCallback& /*callback*/, - std::unique_ptr<Request>* /*request*/, - const NetLogWithSource& net_log) override { - return resolver_->GetProxyForURL(url, results, bindings_.get()); - } - - private: - std::unique_ptr<ProxyResolverV8> resolver_; - std::unique_ptr<MockJSBindings> bindings_; - - DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Wrapper); -}; - -class ProxyResolverV8Factory : public ProxyResolverFactory { - public: - ProxyResolverV8Factory() : ProxyResolverFactory(true) {} - int CreateProxyResolver( - const scoped_refptr<ProxyResolverScriptData>& pac_script, - std::unique_ptr<ProxyResolver>* resolver, - const net::CompletionCallback& callback, - std::unique_ptr<Request>* request) override { - std::unique_ptr<ProxyResolverV8> v8_resolver; - std::unique_ptr<MockJSBindings> js_bindings_(new MockJSBindings); - int result = - ProxyResolverV8::Create(pac_script, js_bindings_.get(), &v8_resolver); - if (result == OK) { - resolver->reset(new ProxyResolverV8Wrapper(std::move(v8_resolver), - std::move(js_bindings_))); - } - return result; - } - - private: - DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Factory); -}; - -TEST(ProxyResolverPerfTest, ProxyResolverV8) { - base::MessageLoop message_loop; - ProxyResolverV8Factory factory; - PacPerfSuiteRunner runner(&factory, "ProxyResolverV8"); - runner.RunAllTests(); -} - -} // namespace - -} // namespace net
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc index 08699c7e..9fd9d3b 100644 --- a/net/quic/core/congestion_control/bbr_sender.cc +++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -79,6 +79,9 @@ last_sent_packet_(0), current_round_trip_end_(0), max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0), + max_ack_spacing_(kBandwidthWindowSize, QuicTime::Delta::Zero(), 0), + largest_acked_time_(QuicTime::Zero()), + largest_acked_sent_time_(QuicTime::Zero()), min_rtt_(QuicTime::Delta::Zero()), min_rtt_timestamp_(QuicTime::Zero()), congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), @@ -202,6 +205,10 @@ min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), is_round_start); + if (FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_spacing2, 1, 2); + UpdateAckSpacing(event_time, last_acked_packet, acked_packets); + } } // Handle logic specific to PROBE_BW mode. @@ -466,6 +473,41 @@ } } +// TODO(ianswett): Move this logic into BandwidthSampler. +void BbrSender::UpdateAckSpacing(QuicTime ack_time, + QuicPacketNumber largest_newly_acked, + const CongestionVector& acked_packets) { + // Ignore acks of reordered packets. + if (largest_newly_acked < unacked_packets_->largest_observed()) { + return; + } + // Ignore acks of only one packet to filter out delayed acks. + if (acked_packets.size() == 1) { + return; + } + QuicTime largest_newly_acked_sent_time = + unacked_packets_->GetTransmissionInfo(largest_newly_acked).sent_time; + // Initialize on the first ack. + if (!largest_acked_time_.IsInitialized()) { + largest_acked_time_ = ack_time; + largest_acked_sent_time_ = largest_newly_acked_sent_time; + return; + } + QuicTime::Delta ack_delta = ack_time - largest_acked_time_; + QuicTime::Delta send_delta = + largest_newly_acked_sent_time - largest_acked_sent_time_; + largest_acked_time_ = ack_time; + largest_acked_sent_time_ = largest_newly_acked_sent_time; + if (ack_delta <= send_delta) { + return; + } + + // Limit the ack spacing to SRTT to filter outliers. + QuicTime::Delta ack_spacing = + std::min(ack_delta - send_delta, rtt_stats_->smoothed_rtt()); + max_ack_spacing_.Update(ack_spacing, round_trip_count_); +} + void BbrSender::CalculatePacingRate() { if (BandwidthEstimate().IsZero()) { return; @@ -500,18 +542,23 @@ if (rtt_variance_weight_ > 0.f && !BandwidthEstimate().IsZero()) { target_window += rtt_variance_weight_ * rtt_stats_->mean_deviation() * BandwidthEstimate(); + } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2 && + is_at_full_bandwidth_) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_spacing2, 2, 2); + // Add CWND for inter-ack spacing once STARTUP has been exited. + target_window += max_ack_spacing_.GetBest() * BandwidthEstimate(); } // Instead of immediately setting the target CWND as the new one, BBR grows // the CWND towards |target_window| by only increasing it |bytes_acked| at a // time. if (is_at_full_bandwidth_) { - // If the connection is not yet out of startup phase, do not decrease the - // window. congestion_window_ = std::min(target_window, congestion_window_ + bytes_acked); } else if (congestion_window_ < target_window || sampler_.total_bytes_acked() < initial_congestion_window_) { + // If the connection is not yet out of startup phase, do not decrease the + // window. congestion_window_ = congestion_window_ + bytes_acked; }
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h index 7a1089c..b248cd2 100644 --- a/net/quic/core/congestion_control/bbr_sender.h +++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -36,8 +36,6 @@ // pacing is disabled. // // TODO(vasilvv): implement traffic policer (long-term sampling) mode. -// -// TODO(vasilvv): implement packet conservation. class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { public: enum Mode { @@ -143,6 +141,12 @@ QuicRoundTripCount> MaxBandwidthFilter; + typedef WindowedFilter<QuicTime::Delta, + MaxFilter<QuicTime::Delta>, + QuicRoundTripCount, + QuicRoundTripCount> + MaxAckDelayFilter; + // Returns the current estimate of the RTT of the connection. Outside of the // edge cases, this is minimum RTT. QuicTime::Delta GetMinRtt() const; @@ -186,6 +190,11 @@ bool has_losses, bool is_round_start); + // Updates the ack spacing max filter if a larger value is observed. + void UpdateAckSpacing(QuicTime ack_time, + QuicPacketNumber largest_newly_acked, + const CongestionVector& acked_packets); + // Determines the appropriate pacing rate for the connection. void CalculatePacingRate(); // Determines the appropriate congestion window for the connection. @@ -217,6 +226,13 @@ // round-trips. MaxBandwidthFilter max_bandwidth_; + // Tracks the maximum spacing between two acks acknowledging in order packets. + MaxAckDelayFilter max_ack_spacing_; + + // The time the largest acked packet was acked and when it was sent. + QuicTime largest_acked_time_; + QuicTime largest_acked_sent_time_; + // Minimum RTT estimate. Automatically expires within 10 seconds (and // triggers PROBE_RTT mode) if no new value is sampled during that period. QuicTime::Delta min_rtt_;
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc index d987655..64c0a15a 100644 --- a/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -136,6 +136,13 @@ kTestPropagationDelay)); } + void EnableAggregation(QuicByteCount aggregation_bytes, + QuicTime::Delta aggregation_timeout) { + // Enable aggregation on the path from the receiver to the sender. + switch_->port_queue(1)->EnableAggregation(aggregation_bytes, + aggregation_timeout); + } + void DoSimpleTransfer(QuicByteCount transfer_size, QuicTime::Delta deadline) { bbr_sender_.AddBytesToTransfer(transfer_size); bool simulator_result = simulator_.RunUntilOrTimeout( @@ -224,6 +231,29 @@ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); } +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, DISABLED_SimpleTransfer2RTTAggregation) { + QuicFlagSaver flags; + FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2 = true; + CreateDefaultSetup(); + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * kTestRtt); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 25% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.25f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + // Test the number of losses incurred by the startup phase in a situation when // the buffer is less than BDP. TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartup) {
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 25b97cec..36ec22e 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -82,10 +82,6 @@ FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer, true) -// If true, buffer packets while parsing public headers instead of parsing down -// if CHLO is already buffered. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo, true) - // If true, do not override a connection in global map if exists. Only create // QUIC session if it is successfully inserted to the global map. Toss the // packet if insertion fails. @@ -171,3 +167,13 @@ // If true, multipath bit is not used in public flag. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_multipath_bit, false) + +// Allow QUIC's flow control autotuning to increase the window as +// quickly for the first adjustment as in subsequent ones. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune, + false) + +// Only consider using the ack spacing in QUIC BBR if 2 packets are acked at +// once. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2, false)
diff --git a/net/quic/core/quic_flow_controller.cc b/net/quic/core/quic_flow_controller.cc index d519032a..1c27276 100644 --- a/net/quic/core/quic_flow_controller.cc +++ b/net/quic/core/quic_flow_controller.cc
@@ -7,8 +7,10 @@ #include <cstdint> #include "net/quic/core/quic_connection.h" +#include "net/quic/core/quic_flags.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_str_cat.h" @@ -184,6 +186,14 @@ QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_; QuicByteCount threshold = WindowUpdateThreshold(); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune && + !prev_window_update_time_.IsInitialized()) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_flow_control_faster_autotune); + // Treat the initial window as if it is a window update, so if 1/2 the + // window is used in less than 2 RTTs, the window is increased. + prev_window_update_time_ = connection_->clock()->ApproximateNow(); + } + if (available_window >= threshold) { QUIC_DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_ << ", available window: " << available_window
diff --git a/net/quic/core/quic_flow_controller_test.cc b/net/quic/core/quic_flow_controller_test.cc index 9e8eb45..ee80f75 100644 --- a/net/quic/core/quic_flow_controller_test.cc +++ b/net/quic/core/quic_flow_controller_test.cc
@@ -38,7 +38,9 @@ : stream_id_(1234), send_window_(kInitialSessionFlowControlWindowForTest), receive_window_(kInitialSessionFlowControlWindowForTest), - connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT) {} + connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT) { + FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune = true; + } void Initialize() { flow_controller_.reset(new QuicFlowController( @@ -55,6 +57,7 @@ MockAlarmFactory alarm_factory_; MockQuicConnection connection_; MockFlowController session_flow_controller_; + QuicFlagSaver flag_saver_; }; TEST_F(QuicFlowControllerTest, SendingBytes) { @@ -165,7 +168,13 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) { // This test will generate two WINDOW_UPDATE frames. - EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)) + .Times(1); + } else { + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)) + .Times(2); + } Initialize(); flow_controller_->set_auto_tune_receive_window(true); @@ -195,20 +204,32 @@ EXPECT_FALSE(flow_controller_->FlowControlViolation()); EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset, QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_CALL( + session_flow_controller_, + EnsureWindowAtLeast(kInitialSessionFlowControlWindowForTest * 2 * 1.5)); + } // Consume enough bytes to send a WINDOW_UPDATE frame. flow_controller_->AddBytesConsumed(threshold + 1); // Result is that once again we have a fully open receive window. EXPECT_FALSE(flow_controller_->FlowControlViolation()); - EXPECT_EQ(kInitialSessionFlowControlWindowForTest, - QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_EQ( + 2 * kInitialSessionFlowControlWindowForTest, + QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + } else { + EXPECT_EQ( + kInitialSessionFlowControlWindowForTest, + QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); - // Move time forward, but by less than two RTTs. Then receive and consume - // some more, forcing a second WINDOW_UPDATE with an increased max window - // size. - EXPECT_CALL( - session_flow_controller_, - EnsureWindowAtLeast(kInitialSessionFlowControlWindowForTest * 2 * 1.5)); + // Move time forward, but by less than two RTTs. Then receive and consume + // some more, forcing a second WINDOW_UPDATE with an increased max window + // size. + EXPECT_CALL( + session_flow_controller_, + EnsureWindowAtLeast(kInitialSessionFlowControlWindowForTest * 2 * 1.5)); + } connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1)); receive_offset += threshold + 1; @@ -275,7 +296,13 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) { // This test will generate two WINDOW_UPDATE frames. - EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)) + .Times(1); + } else { + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)) + .Times(2); + } Initialize(); flow_controller_->set_auto_tune_receive_window(true); @@ -304,13 +331,24 @@ EXPECT_FALSE(flow_controller_->FlowControlViolation()); EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset, QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); - + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_CALL( + session_flow_controller_, + EnsureWindowAtLeast(kInitialSessionFlowControlWindowForTest * 2 * 1.5)); + } flow_controller_->AddBytesConsumed(threshold + 1); // Result is that once again we have a fully open receive window. EXPECT_FALSE(flow_controller_->FlowControlViolation()); - EXPECT_EQ(kInitialSessionFlowControlWindowForTest, - QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_EQ( + 2 * kInitialSessionFlowControlWindowForTest, + QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + } else { + EXPECT_EQ( + kInitialSessionFlowControlWindowForTest, + QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); + } // Move time forward, but by more than two RTTs. Then receive and consume // some more, forcing a second WINDOW_UPDATE with unchanged max window size. @@ -324,8 +362,11 @@ QuicByteCount new_threshold = QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get()); - - EXPECT_EQ(new_threshold, threshold); + if (FLAGS_quic_reloadable_flag_quic_flow_control_faster_autotune) { + EXPECT_EQ(new_threshold, 2 * threshold); + } else { + EXPECT_EQ(new_threshold, threshold); + } } TEST_F(QuicFlowControllerTest, ReceivingBytesNormalNoAutoTune) {
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 785319e..3dfb5d84 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -437,7 +437,9 @@ NetLogWithSource log; HttpNetworkSession* session = helper.session(); base::WeakPtr<SpdySession> spdy_session = - session->spdy_session_pool()->FindAvailableSession(key, url, log); + session->spdy_session_pool()->FindAvailableSession( + key, url, + /* enable_ip_based_pooling = */ true, log); ASSERT_TRUE(spdy_session); EXPECT_EQ(0u, spdy_session->num_active_streams()); EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); @@ -4057,7 +4059,9 @@ PRIVACY_MODE_DISABLED); NetLogWithSource log; base::WeakPtr<SpdySession> spdy_session = - spdy_session_pool->FindAvailableSession(key, GURL(), log); + spdy_session_pool->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, log); EXPECT_TRUE(spdy_session); // Start second transaction. @@ -4087,7 +4091,9 @@ EXPECT_EQ("hello!", response_data); // Graceful GOAWAY was received, SpdySession should be unavailable. - spdy_session = spdy_session_pool->FindAvailableSession(key, GURL(), log); + spdy_session = spdy_session_pool->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, log); EXPECT_FALSE(spdy_session); helper.VerifyDataConsumed(); @@ -5035,7 +5041,9 @@ SpdySessionKey key(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> spdy_session = - spdy_session_pool->FindAvailableSession(key, GURL(), log); + spdy_session_pool->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, log); EXPECT_FALSE(spdy_session->unclaimed_pushed_streams_.empty()); EXPECT_EQ(1u, spdy_session->unclaimed_pushed_streams_.size()); @@ -5182,7 +5190,9 @@ SpdySessionKey key0(host_port_pair0, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> spdy_session0 = - spdy_session_pool->FindAvailableSession(key0, GURL(), log); + spdy_session_pool->FindAvailableSession( + key0, GURL(), + /* enable_ip_based_pooling = */ true, log); EXPECT_TRUE(spdy_session0->unclaimed_pushed_streams_.empty()); EXPECT_EQ(0u, spdy_session0->unclaimed_pushed_streams_.size()); @@ -5191,7 +5201,9 @@ SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); base::WeakPtr<SpdySession> spdy_session1 = - spdy_session_pool->FindAvailableSession(key1, GURL(), log); + spdy_session_pool->FindAvailableSession( + key1, GURL(), + /* enable_ip_based_pooling = */ true, log); EXPECT_FALSE(spdy_session1->unclaimed_pushed_streams_.empty()); EXPECT_EQ(1u, spdy_session1->unclaimed_pushed_streams_.size());
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 2b47a81..e217fc2a 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -1332,6 +1332,10 @@ pooled_aliases_.insert(alias_key); } +void SpdySession::RemovePooledAlias(const SpdySessionKey& alias_key) { + pooled_aliases_.erase(alias_key); +} + bool SpdySession::HasAcceptableTransportSecurity() const { // If we're not even using TLS, we have no standards to meet. if (!is_secure_) {
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 9852e2d6..d6f03c3 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h
@@ -532,6 +532,9 @@ // Adds |alias| to set of aliases associated with this session. void AddPooledAlias(const SpdySessionKey& alias_key); + // Removes |alias| from set of aliases associated with this session. + void RemovePooledAlias(const SpdySessionKey& alias_key); + // Returns the set of aliases associated with this session. const std::set<SpdySessionKey>& pooled_aliases() const { return pooled_aliases_;
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index 308a80b1e..7850b4f 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc
@@ -130,6 +130,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession( const SpdySessionKey& key, const GURL& url, + bool enable_ip_based_pooling, const NetLogWithSource& net_log) { UnclaimedPushedStreamMap::iterator url_it = unclaimed_pushed_streams_.find(url); @@ -169,6 +170,16 @@ NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION, it->second->net_log().source().ToEventParametersCallback()); } else { + if (!enable_ip_based_pooling) { + // Remove session from available sessions and from aliases, and remove + // key from the session's pooled alias set, so that a new session can be + // created with this |key|. + it->second->RemovePooledAlias(key); + UnmapKey(key); + RemoveAliases(key); + return base::WeakPtr<SpdySession>(); + } + UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", FOUND_EXISTING_FROM_IP_POOL, SPDY_SESSION_GET_MAX); @@ -180,6 +191,9 @@ return it->second; } + if (!enable_ip_based_pooling) + return base::WeakPtr<SpdySession>(); + // Look up IP addresses from resolver cache. HostResolver::RequestInfo resolve_info(key.host_port_pair()); AddressList addresses;
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index fc82c40..9da2fb7a 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h
@@ -87,12 +87,19 @@ const NetLogWithSource& net_log, bool is_secure); - // Return an available session for |key| that has an unclaimed push stream for - // |url| if such exists and |url| is not empty, or else an available session - // for |key| if such exists, or else nullptr. + // If |url| is not empty and there is a session for |key| that has an + // unclaimed push stream for |url|, return it. + // Otherwise if there is an available session for |key|, return it. + // Otherwise if there is a session to pool to based on IP address: + // * if |enable_ip_based_pooling == true|, + // then mark it as available for |key| and return it; + // * if |enable_ip_based_pooling == false|, + // then remove it from the available sessions, and return nullptr. + // Otherwise return nullptr. base::WeakPtr<SpdySession> FindAvailableSession( const SpdySessionKey& key, const GURL& url, + bool enable_ip_based_pooling, const NetLogWithSource& net_log); // Remove all mappings and aliases for the given session, which must
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc index 7c69a0b8..2d0d845 100644 --- a/net/spdy/spdy_session_pool_unittest.cc +++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -419,7 +419,8 @@ // we got with host 0, and that is a different from host 2's session. base::WeakPtr<SpdySession> session1 = spdy_session_pool_->FindAvailableSession( - test_hosts[1].key, GURL(test_hosts[1].url), NetLogWithSource()); + test_hosts[1].key, GURL(test_hosts[1].url), + /* enable_ip_based_pooling = */ true, NetLogWithSource()); EXPECT_EQ(session.get(), session1.get()); EXPECT_NE(session2.get(), session1.get()); @@ -560,16 +561,18 @@ BoundTestNetLog net_log; base::HistogramTester histogram_tester; base::WeakPtr<SpdySession> session1 = - spdy_session_pool_->FindAvailableSession(test_hosts[1].key, GURL(), - net_log.bound()); + spdy_session_pool_->FindAvailableSession( + test_hosts[1].key, GURL(), + /* enable_ip_based_pooling = */ true, net_log.bound()); EXPECT_EQ(session0.get(), session1.get()); ASSERT_EQ(1u, net_log.GetSize()); histogram_tester.ExpectTotalCount("Net.SpdySessionGet", 1); // A request to the second host should still pool to the existing connection. - session1 = spdy_session_pool_->FindAvailableSession(test_hosts[1].key, GURL(), - net_log.bound()); + session1 = spdy_session_pool_->FindAvailableSession( + test_hosts[1].key, GURL(), + /* enable_ip_based_pooling = */ true, net_log.bound()); EXPECT_EQ(session0.get(), session1.get()); ASSERT_EQ(2u, net_log.GetSize()); @@ -591,6 +594,78 @@ histogram_tester.ExpectUniqueSample("Net.SpdySessionGet", 2, 2); } +TEST_F(SpdySessionPoolTest, IPPoolingDisabled) { + // Define two hosts with identical IP address. + const int kTestPort = 443; + struct TestHosts { + std::string name; + std::string iplist; + SpdySessionKey key; + AddressList addresses; + std::unique_ptr<HostResolver::Request> request; + } test_hosts[] = { + {"www.example.org", "192.168.0.1"}, {"mail.example.org", "192.168.0.1"}, + }; + + // Populate the HostResolver cache. + session_deps_.host_resolver->set_synchronous_mode(true); + for (size_t i = 0; i < arraysize(test_hosts); i++) { + session_deps_.host_resolver->rules()->AddIPLiteralRule( + test_hosts[i].name, test_hosts[i].iplist, std::string()); + + HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort)); + session_deps_.host_resolver->Resolve( + info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(), + &test_hosts[i].request, NetLogWithSource()); + + test_hosts[i].key = + SpdySessionKey(HostPortPair(test_hosts[i].name, kTestPort), + ProxyServer::Direct(), PRIVACY_MODE_DISABLED); + } + + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; + StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0); + MockConnect connect_data(SYNCHRONOUS, OK); + data.set_connect_data(connect_data); + session_deps_.socket_factory->AddSocketDataProvider(&data); + AddSSLSocketData(); + + MockRead reads1[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; + StaticSocketDataProvider data1(reads1, arraysize(reads1), nullptr, 0); + MockConnect connect_data1(SYNCHRONOUS, OK); + data1.set_connect_data(connect_data1); + session_deps_.socket_factory->AddSocketDataProvider(&data1); + AddSSLSocketData(); + + CreateNetworkSession(); + + // Open SpdySession to the first host. + base::WeakPtr<SpdySession> session0 = CreateSecureSpdySession( + http_session_.get(), test_hosts[0].key, NetLogWithSource()); + + // A request to the second host should pool to the existing connection. + base::WeakPtr<SpdySession> session1 = + spdy_session_pool_->FindAvailableSession( + test_hosts[1].key, GURL(), + /* enable_ip_based_pooling = */ true, NetLogWithSource()); + EXPECT_EQ(session0.get(), session1.get()); + + // A request to the second host should not pool to the existing connection if + // IP based pooling is disabled. + session1 = spdy_session_pool_->FindAvailableSession( + test_hosts[1].key, GURL(), + /* enable_ip_based_pooling = */ false, NetLogWithSource()); + EXPECT_FALSE(session1); + + // It should be possible to open a new SpdySession, even if a previous call to + // FindAvailableSession() linked the second key to the first connection in the + // IP pooled bucket of SpdySessionPool::available_session_map_. + session1 = CreateSecureSpdySessionWithIpBasedPoolingDisabled( + http_session_.get(), test_hosts[1].key, NetLogWithSource()); + EXPECT_TRUE(session1); + EXPECT_NE(session0.get(), session1.get()); +} + // Construct a Pool with SpdySessions in various availability states. Simulate // an IP address change. Ensure sessions gracefully shut down. Regression test // for crbug.com/379469. @@ -740,14 +815,17 @@ // FindAvailableSession should return |session| if called with empty |url|. base::WeakPtr<SpdySession> session1 = - spdy_session_pool_->FindAvailableSession(key, GURL(), NetLogWithSource()); + spdy_session_pool_->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, NetLogWithSource()); EXPECT_EQ(session.get(), session1.get()); // FindAvailableSession should return |session| if called with |url| for which // there is no pushed stream on any sessions owned by |spdy_session_pool_|. base::WeakPtr<SpdySession> session2 = spdy_session_pool_->FindAvailableSession( - key, GURL("http://news.example.org/foo.html"), NetLogWithSource()); + key, GURL("http://news.example.org/foo.html"), + /* enable_ip_based_pooling = */ true, NetLogWithSource()); EXPECT_EQ(session.get(), session2.get()); spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index cc64f1b..7be6c367b 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc
@@ -3428,8 +3428,9 @@ NetLogWithSource()); // Get a session for |key2|, which should return the session created earlier. base::WeakPtr<SpdySession> session2 = - spdy_session_pool_->FindAvailableSession(key2, GURL(), - NetLogWithSource()); + spdy_session_pool_->FindAvailableSession( + key2, GURL(), + /* enable_ip_based_pooling = */ true, NetLogWithSource()); ASSERT_EQ(session1.get(), session2.get()); EXPECT_FALSE(pool->IsStalled());
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 1b2ef247..53a3bfe6 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -25,6 +25,7 @@ #include "net/http/http_network_transaction.h" #include "net/http/http_server_properties_impl.h" #include "net/log/net_log_with_source.h" +#include "net/socket/client_socket_handle.h" #include "net/socket/next_proto.h" #include "net/socket/socket_test_util.h" #include "net/socket/ssl_client_socket.h" @@ -484,8 +485,9 @@ } bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) { - return static_cast<bool>( - pool->FindAvailableSession(key, GURL(), NetLogWithSource())); + return static_cast<bool>(pool->FindAvailableSession( + key, GURL(), + /* enable_ip_based_pooling = */ true, NetLogWithSource())); } namespace { @@ -495,8 +497,10 @@ const SpdySessionKey& key, const NetLogWithSource& net_log, Error expected_status, - bool is_secure) { - EXPECT_FALSE(HasSpdySession(http_session->spdy_session_pool(), key)); + bool is_secure, + bool enable_ip_based_pooling) { + EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession( + key, GURL(), enable_ip_based_pooling, NetLogWithSource())); scoped_refptr<TransportSocketParams> transport_params( new TransportSocketParams( @@ -552,8 +556,9 @@ HttpNetworkSession* http_session, const SpdySessionKey& key, const NetLogWithSource& net_log) { - return CreateSpdySessionHelper(http_session, key, net_log, - OK, false /* is_secure */); + return CreateSpdySessionHelper(http_session, key, net_log, OK, + /* is_secure = */ false, + /* enable_ip_based_pooling = */ true); } base::WeakPtr<SpdySession> TryCreateSpdySessionExpectingFailure( @@ -563,15 +568,26 @@ const NetLogWithSource& net_log) { DCHECK_LT(expected_error, ERR_IO_PENDING); return CreateSpdySessionHelper(http_session, key, net_log, expected_error, - true /* is_secure */); + /* is_secure = */ true, + /* enable_ip_based_pooling = */ true); } base::WeakPtr<SpdySession> CreateSecureSpdySession( HttpNetworkSession* http_session, const SpdySessionKey& key, const NetLogWithSource& net_log) { - return CreateSpdySessionHelper(http_session, key, net_log, - OK, true /* is_secure */); + return CreateSpdySessionHelper(http_session, key, net_log, OK, + /* is_secure = */ true, + /* enable_ip_based_pooling = */ true); +} + +base::WeakPtr<SpdySession> CreateSecureSpdySessionWithIpBasedPoolingDisabled( + HttpNetworkSession* http_session, + const SpdySessionKey& key, + const NetLogWithSource& net_log) { + return CreateSpdySessionHelper(http_session, key, net_log, OK, + /* is_secure = */ true, + /* enable_ip_based_pooling = */ false); } namespace {
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 62a0564..7672ece5 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -258,6 +258,13 @@ const SpdySessionKey& key, const NetLogWithSource& net_log); +// Like CreateSecureSpdySession(), but does not fail if there is already an IP +// pooled session for |key|. +base::WeakPtr<SpdySession> CreateSecureSpdySessionWithIpBasedPoolingDisabled( + HttpNetworkSession* http_session, + const SpdySessionKey& key, + const NetLogWithSource& net_log); + // Creates an insecure SPDY session for the given key and puts it in // |pool|. The returned session will neither receive nor send any // data. A SPDY session for |key| must not already exist.
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 9fba8c4..8768eaf 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -269,8 +269,7 @@ return false; } - if (FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo && - buffered_packets_.HasChloForConnection(connection_id)) { + if (buffered_packets_.HasChloForConnection(connection_id)) { BufferEarlyPacket(connection_id); return false; } @@ -718,23 +717,18 @@ FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop && new_sessions_allowed_per_event_loop_ <= 0) { // Can't create new session any more. Wait till next event loop. - if (!buffered_packets_.HasChloForConnection(current_connection_id_)) { - // Only buffer one CHLO per connection. Remove this condition check when - // --quic_reloadable_flag_quic_buffer_packets_after_chlo - // is deprecated because after that retransmitted CHLO should be buffered - // earlier in OnUnauthenticatedPublicHeader(). - bool is_new_connection = - !buffered_packets_.HasBufferedPackets(current_connection_id_); - EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( - current_connection_id_, *current_packet_, current_server_address_, - current_client_address_, /*is_chlo=*/true); - if (rs != EnqueuePacketResult::SUCCESS) { - OnBufferPacketFailure(rs, current_connection_id_); - } else if ( - !FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && - is_new_connection) { - ShouldCreateOrBufferPacketForConnection(current_connection_id_); - } + QUIC_BUG_IF(buffered_packets_.HasChloForConnection(current_connection_id_)); + bool is_new_connection = + !buffered_packets_.HasBufferedPackets(current_connection_id_); + EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( + current_connection_id_, *current_packet_, current_server_address_, + current_client_address_, /*is_chlo=*/true); + if (rs != EnqueuePacketResult::SUCCESS) { + OnBufferPacketFailure(rs, current_connection_id_); + } else if ( + !FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && + is_new_connection) { + ShouldCreateOrBufferPacketForConnection(current_connection_id_); } return; }
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 621890ab..90b8e2a6 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -1471,10 +1471,6 @@ ProcessPacket(client_addr_, last_connection, true, SerializeFullCHLO()); size_t packets_buffered = 2; - if (!FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo) { - // The packet sent above is dropped when flag is off. - packets_buffered = 1; - } // Reset counter and process buffered CHLO. EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_))
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 4a339f5..e586b50ac 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc
@@ -732,7 +732,7 @@ // Just ignore the message if it's received before Connect() is called. It's // likely to be a leftover from a previous session, so it's safe to ignore it. if (signal_strategy_) - signal_strategy_->OnIncomingMessage(iq); + signal_strategy_->GetIncomingMessageCallback().Run(iq); } void ChromotingInstance::HandleReleaseAllKeys(
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc index 41e8f75e..5636006 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.cc +++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -296,11 +296,14 @@ return; } - delegating_signal_strategy_ = new DelegatingSignalStrategy( - local_jid, host_context_->network_task_runner(), - base::Bind(&It2MeNativeMessagingHost::SendOutgoingIq, - weak_factory_.GetWeakPtr())); - signal_strategy.reset(delegating_signal_strategy_); + auto delegating_signal_strategy = + base::MakeUnique<DelegatingSignalStrategy>( + local_jid, host_context_->network_task_runner(), + base::Bind(&It2MeNativeMessagingHost::SendOutgoingIq, + weak_factory_.GetWeakPtr())); + incoming_message_callback_ = + delegating_signal_strategy->GetIncomingMessageCallback(); + signal_strategy = std::move(delegating_signal_strategy); } std::string directory_bot_jid = service_urls->directory_bot_jid(); @@ -357,8 +360,7 @@ return; } - if (delegating_signal_strategy_) - delegating_signal_strategy_->OnIncomingMessage(iq); + incoming_message_callback_.Run(iq); SendMessageToClient(std::move(response)); };
diff --git a/remoting/host/it2me/it2me_native_messaging_host.h b/remoting/host/it2me/it2me_native_messaging_host.h index 8560084..b42cda0 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.h +++ b/remoting/host/it2me/it2me_native_messaging_host.h
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "remoting/host/it2me/it2me_host.h" +#include "remoting/signaling/delegating_signal_strategy.h" #if !defined(OS_CHROMEOS) #include "remoting/host/native_messaging/log_message_handler.h" @@ -28,7 +29,6 @@ namespace remoting { class ChromotingHostContext; -class DelegatingSignalStrategy; class ElevatedNativeMessagingHost; class PolicyWatcher; @@ -94,7 +94,7 @@ #endif // defined(OS_WIN) Client* client_ = nullptr; - DelegatingSignalStrategy* delegating_signal_strategy_ = nullptr; + DelegatingSignalStrategy::IqCallback incoming_message_callback_; std::unique_ptr<ChromotingHostContext> host_context_; std::unique_ptr<It2MeHostFactory> factory_; scoped_refptr<It2MeHost> it2me_host_;
diff --git a/remoting/signaling/delegating_signal_strategy.cc b/remoting/signaling/delegating_signal_strategy.cc index 83f23907..0f6dc7d 100644 --- a/remoting/signaling/delegating_signal_strategy.cc +++ b/remoting/signaling/delegating_signal_strategy.cc
@@ -16,23 +16,41 @@ DelegatingSignalStrategy::DelegatingSignalStrategy( std::string local_jid, scoped_refptr<base::SingleThreadTaskRunner> client_task_runner, - const SendIqCallback& send_iq_callback) + const IqCallback& send_iq_callback) : local_jid_(local_jid), delegate_task_runner_(base::ThreadTaskRunnerHandle::Get()), client_task_runner_(client_task_runner), send_iq_callback_(send_iq_callback), - weak_factory_(this) {} + weak_factory_(this) { + incoming_iq_callback_ = + base::BindRepeating(&OnIncomingMessageFromDelegate, + weak_factory_.GetWeakPtr(), client_task_runner_); +} DelegatingSignalStrategy::~DelegatingSignalStrategy() {} -void DelegatingSignalStrategy::OnIncomingMessage(const std::string& message) { - if (!client_task_runner_->BelongsToCurrentThread()) { - client_task_runner_->PostTask( - FROM_HERE, base::Bind(&DelegatingSignalStrategy::OnIncomingMessage, - weak_factory_.GetWeakPtr(), message)); +DelegatingSignalStrategy::IqCallback +DelegatingSignalStrategy::GetIncomingMessageCallback() { + return incoming_iq_callback_; +} + +// static +void DelegatingSignalStrategy::OnIncomingMessageFromDelegate( + base::WeakPtr<DelegatingSignalStrategy> weak_ptr, + scoped_refptr<base::SingleThreadTaskRunner> client_task_runner, + const std::string& message) { + if (client_task_runner->BelongsToCurrentThread()) { + weak_ptr->OnIncomingMessage(message); return; } + client_task_runner->PostTask( + FROM_HERE, base::Bind(&DelegatingSignalStrategy::OnIncomingMessage, + weak_ptr, message)); +} + +void DelegatingSignalStrategy::OnIncomingMessage(const std::string& message) { + DCHECK(client_task_runner_->BelongsToCurrentThread()); std::unique_ptr<buzz::XmlElement> stanza(buzz::XmlElement::ForStr(message)); if (!stanza.get()) { LOG(WARNING) << "Malformed XMPP stanza received: " << message;
diff --git a/remoting/signaling/delegating_signal_strategy.h b/remoting/signaling/delegating_signal_strategy.h index 0b6d927..d41de42 100644 --- a/remoting/signaling/delegating_signal_strategy.h +++ b/remoting/signaling/delegating_signal_strategy.h
@@ -21,25 +21,26 @@ // // Notes on thread safety: // 1. This object can be created on any thread. -// 2. OnIncomingMessage() must be called on the same thread on which this object -// is created. -// 3. |send_iq_callback| will always be called on the thread that it is created. +// 2. |send_iq_callback| will always be called on the thread that it is created. // Note that |send_iq_callback| may be called after this object is destroyed. -// 4. The caller should invoke all methods on the SignalStrategy interface on +// 3. The caller should invoke all methods on the SignalStrategy interface on // the |client_task_runner|. -// 5. All listeners will be called on |client_task_runner| as well. -// 6. The destructor should always be called on the |client_task_runner|. +// 4. All listeners will be called on |client_task_runner| as well. +// 5. The destructor should always be called on the |client_task_runner|. +// 6. As a result of (5), use MakeIncomingMessageCallback() to obtain a callback +// when passing incoming signaling messages from the delegate. The callback +// can then be invoked at any thread. class DelegatingSignalStrategy : public SignalStrategy { public: - typedef base::Callback<void(const std::string&)> SendIqCallback; + typedef base::RepeatingCallback<void(const std::string&)> IqCallback; DelegatingSignalStrategy( std::string local_jid, scoped_refptr<base::SingleThreadTaskRunner> client_task_runner, - const SendIqCallback& send_iq_callback); + const IqCallback& send_iq_callback); ~DelegatingSignalStrategy() override; - void OnIncomingMessage(const std::string& message); + IqCallback GetIncomingMessageCallback(); // SignalStrategy interface. void Connect() override; @@ -53,11 +54,19 @@ std::string GetNextId() override; private: + static void OnIncomingMessageFromDelegate( + base::WeakPtr<DelegatingSignalStrategy> weak_ptr, + scoped_refptr<base::SingleThreadTaskRunner> client_task_runner, + const std::string& message); + + void OnIncomingMessage(const std::string& message); + std::string local_jid_; scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_; - SendIqCallback send_iq_callback_; + IqCallback incoming_iq_callback_; + IqCallback send_iq_callback_; base::ObserverList<Listener> listeners_; base::WeakPtrFactory<DelegatingSignalStrategy> weak_factory_;
diff --git a/services/image_decoder/image_decoder_impl.cc b/services/image_decoder/image_decoder_impl.cc index 30c2fe9..53aa56a 100644 --- a/services/image_decoder/image_decoder_impl.cc +++ b/services/image_decoder/image_decoder_impl.cc
@@ -15,7 +15,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #if defined(OS_CHROMEOS) -#include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h" +#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h" #include "ui/gfx/codec/png_codec.h" #endif
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 572edd2..cdce1fd 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -220,10 +220,6 @@ # define SK_USE_LEGACY_DISTANCE_FIELDS #endif -#ifndef SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES -# define SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES -#endif - #ifndef SK_SUPPORT_LEGACY_PATHEFFECT_SUBCLASSES #define SK_SUPPORT_LEGACY_PATHEFFECT_SUBCLASSES #endif
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 824caef..ddf9de8 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -17,7 +17,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -49,7 +49,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -80,7 +80,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -111,7 +111,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -143,7 +143,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -174,7 +174,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -205,7 +205,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -239,7 +239,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -271,7 +271,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -302,7 +302,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -336,7 +336,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -368,7 +368,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -399,7 +399,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -430,7 +430,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -461,7 +461,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -492,7 +492,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -523,7 +523,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -555,7 +555,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -586,7 +586,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -617,7 +617,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -648,7 +648,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -679,7 +679,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -711,7 +711,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -743,7 +743,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -775,7 +775,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -807,7 +807,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -842,7 +842,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -874,7 +874,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -905,7 +905,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -936,7 +936,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -968,7 +968,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -999,7 +999,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1030,7 +1030,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1061,7 +1061,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1092,7 +1092,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1123,7 +1123,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1154,7 +1154,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:3ff24775a900b675866fbcacf2a8f98a18b2a16a" } ], "dimension_sets": [ @@ -1333,7 +1333,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1366,7 +1366,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1402,7 +1402,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1435,7 +1435,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1468,7 +1468,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1501,7 +1501,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1534,7 +1534,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1567,7 +1567,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1600,7 +1600,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1633,7 +1633,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1666,7 +1666,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1699,7 +1699,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1732,7 +1732,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1765,7 +1765,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1798,7 +1798,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1831,7 +1831,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1864,7 +1864,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1897,7 +1897,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1930,7 +1930,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1966,7 +1966,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1999,7 +1999,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2032,7 +2032,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2065,7 +2065,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2098,7 +2098,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2131,7 +2131,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2164,7 +2164,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2197,7 +2197,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2233,7 +2233,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2269,7 +2269,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2305,7 +2305,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2341,7 +2341,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2483,7 +2483,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2517,7 +2517,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2548,7 +2548,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2579,7 +2579,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2613,7 +2613,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2644,7 +2644,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2675,7 +2675,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2710,7 +2710,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2744,7 +2744,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2775,7 +2775,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2810,7 +2810,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2841,7 +2841,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2876,7 +2876,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2907,7 +2907,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2942,7 +2942,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2976,7 +2976,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3007,7 +3007,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3042,7 +3042,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3073,7 +3073,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3104,7 +3104,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3135,7 +3135,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3166,7 +3166,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3197,7 +3197,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3228,7 +3228,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3259,7 +3259,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3290,7 +3290,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3321,7 +3321,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3352,7 +3352,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3386,7 +3386,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3417,7 +3417,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3448,7 +3448,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -3479,7 +3479,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index c0b5ad2..1c859c24 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -11473,6 +11473,22 @@ } ] }, + "Ozone Linux": { + "gtest_tests": [ + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mus_demo_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mus_ws_unittests" + } + ] + }, "Site Isolation Android": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index e05e1bf..ca3449d 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -33,7 +33,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -65,7 +65,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -96,7 +96,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -127,7 +127,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -159,7 +159,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -190,7 +190,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -221,7 +221,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -255,7 +255,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -290,7 +290,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -322,7 +322,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -353,7 +353,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -384,7 +384,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -419,7 +419,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -451,7 +451,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -482,7 +482,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -513,7 +513,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -544,7 +544,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -575,7 +575,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -607,7 +607,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -638,7 +638,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -669,7 +669,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -700,7 +700,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -731,7 +731,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -763,7 +763,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -795,7 +795,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -827,7 +827,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -859,7 +859,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -894,7 +894,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -926,7 +926,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -957,7 +957,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -988,7 +988,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1019,7 +1019,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1050,7 +1050,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1081,7 +1081,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1112,7 +1112,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1143,7 +1143,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1248,7 +1248,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1280,7 +1280,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1311,7 +1311,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1342,7 +1342,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1374,7 +1374,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1405,7 +1405,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1436,7 +1436,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1470,7 +1470,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1505,7 +1505,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1537,7 +1537,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1568,7 +1568,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1599,7 +1599,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1634,7 +1634,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1666,7 +1666,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1697,7 +1697,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1728,7 +1728,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1759,7 +1759,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1790,7 +1790,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1822,7 +1822,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1853,7 +1853,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1884,7 +1884,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1915,7 +1915,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1946,7 +1946,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -1978,7 +1978,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2010,7 +2010,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2042,7 +2042,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2074,7 +2074,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2109,7 +2109,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2141,7 +2141,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2172,7 +2172,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2203,7 +2203,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2235,7 +2235,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2266,7 +2266,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2297,7 +2297,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2328,7 +2328,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2359,7 +2359,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [ @@ -2390,7 +2390,7 @@ { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + "revision": "git_revision:dec8cc6fd715753846d0aca1693dc63844ea55d6" } ], "dimension_sets": [
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 5b775b2..1500fd9 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -65,6 +65,9 @@ crbug.com/662477 external/wpt/html/webappapis/idle-callbacks/cancel-invoked.html [ Leak ] crbug.com/662477 external/wpt/html/webappapis/scripting/events/onerroreventhandler.html [ Leak ] +# Likely caused by http://crbug.com/501866. +crbug.com/701695 external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-errorevent.html [ Leak ] + # ----------------------------------------------------------------- # Untriaged but known leaks of ActiveDOMObject (fast). # -----------------------------------------------------------------
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index a9a0d99..61a76cc4 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -7,9 +7,6 @@ # failure. Expected outputs will be adjusted for the better once Oilpan # has been well and truly enabled always. -crbug.com/420008 inspector/tracing/worker-js-frames.html [ Pass Timeout Failure ] -crbug.com/420008 virtual/threaded/inspector/tracing/worker-js-frames.html [ Pass Timeout Failure ] - crbug.com/569901 crbug.com/24182 [ Debug ] jquery/manipulation.html [ Timeout Pass ] # ====== Oilpan-only failures until here ======
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents-expected.txt new file mode 100644 index 0000000..76926963 --- /dev/null +++ b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents-expected.txt
@@ -0,0 +1,7 @@ +This makes sure we are able to delete the contents of a password field: deleting a selection and evaluating the field contents. + +PASS passwordField.value='helllo'; passwordField.setSelectionRange(3, 4); testRunner.execCommand('Delete', false, null); passwordField.value is 'hello' +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents.html b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents.html new file mode 100644 index 0000000..3e4461b --- /dev/null +++ b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-contents.html
@@ -0,0 +1,32 @@ +<!DOCTYPE> +<html> +<head> +<script src="../../resources/js-test.js"></script> +</head> +<body> +<p id="description">This makes sure we are able to delete the contents of a password field: deleting a selection and evaluating the field contents.</p> +<div id="console"></div> +<input type="password" id="passwordField"> +<script> + +if (!window.testRunner || !window.internals) + testFailed('This test requires access to window.internals'); + +var textField; +var desiredString = "hello"; +function runTest(element) { + textField = element; + + textField.value = "helllo"; + textField.focus(); + + shouldBe("passwordField.value='helllo'; passwordField.setSelectionRange(3, 4); testRunner.execCommand('Delete', false, null); passwordField.value", "'hello'"); + + textField.parentNode.removeChild(textField); +} + +runTest(document.getElementById('passwordField')); + +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance-expected.txt deleted file mode 100644 index b6aa4213..0000000 --- a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This test ensures that deleting characters from a password field that follows large content blocks is not slow. To run the test manually, delete the character from the password field. The user agent should not freeze. - -
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance.html b/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance.html deleted file mode 100644 index ce2520f..0000000 --- a/third_party/WebKit/LayoutTests/editing/deleting/password-delete-performance.html +++ /dev/null
@@ -1,31 +0,0 @@ -<!DOCTYPE html> -<html> - <body> - <p id="description">This test ensures that deleting characters from a password field that follows large content blocks is not slow. - To run the test manually, delete the character from the password field. The user agent should not freeze.</p> - - <div id="content" style="height:0px; overflow:hidden;"> </div> - <input id="field" type="password" value="A"> - - <script src="../editing.js"></script> - <script> - if (window.testRunner) - testRunner.dumpAsText(); - - var newContent = '<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>'; - for (var i = 0; i < 13; i++) { - newContent += newContent; - } - - var contentDiv = document.getElementById('content'); - contentDiv.innerHTML = newContent; - - document.getElementById("field").focus(); - document.execCommand("Delete"); - - // We clear the content div to avoid having its content appear in the test harness output. - if (window.testRunner) - contentDiv.innerHTML = ""; - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index 258ed15..bafc7dc0 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -11550,6 +11550,11 @@ {} ] ], + "html/browsers/windows/browsing-context-names/browsing-context-_blank-expected.txt": [ + [ + {} + ] + ], "html/browsers/windows/browsing-context-names/existing.html": [ [ {} @@ -41454,6 +41459,18 @@ {} ] ], + "html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html": [ + [ + "/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html", + {} + ] + ], + "html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js": [ + [ + "/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.html", + {} + ] + ], "html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html": [ [ "/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html", @@ -65786,7 +65803,7 @@ "support" ], "html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html": [ - "3164df75ba277feef3b5c9a1ff6021f3e51d48de", + "4d0e0901dd42a40d86c7263ac7ac432059b6e84e", "testharness" ], "html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back-1.html": [ @@ -67133,6 +67150,10 @@ "ed586ee147452ba6cb8d90782b266807f8b7975e", "testharness" ], + "html/browsers/windows/browsing-context-names/browsing-context-_blank-expected.txt": [ + "c07a576dcc76bb8d6271442116909f0be5098a77", + "support" + ], "html/browsers/windows/browsing-context-names/browsing-context-_blank.html": [ "4a1a9ff6c913291edce2339faa443b6da2e5fe74", "testharness" @@ -76913,6 +76934,14 @@ "ef22b322a16f835c562a0aa4575361f0fb53754a", "testharness" ], + "html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html": [ + "378f086b3f8e2ea3443be95ee352d9d96604ccd0", + "testharness" + ], + "html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js": [ + "3e8715be8b85623793e9bc18b1202616a5353e10", + "testharness" + ], "html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html": [ "e69a2ad6b52db467bab6baee7485809fec35893c", "testharness" @@ -77898,7 +77927,7 @@ "testharness" ], "mediacapture-streams/MediaStreamTrack-init.https-expected.txt": [ - "e06d937ccc5c05632bc1ce90cb8302d416be5480", + "4e890a8c710bbc3100a3c3fc68a2292cff4afa58", "support" ], "mediacapture-streams/MediaStreamTrack-init.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt index df8492b..dab3404 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt
@@ -1,6 +1,8 @@ This is a testharness.js-based test. PASS Returning a string must not cancel the event: CustomEvent, non-cancelable PASS Returning a string must not cancel the event: CustomEvent, cancelable +FAIL Returning false must cancel the event, because it's coerced to the DOMString "false" which does not cancel CustomEvents: CustomEvent, cancelable assert_false: The event must not have been canceled expected false got true +PASS Returning a string must not cancel the event: BeforeUnloadEvent with type "click", cancelable PASS Returning null with a real iframe unloading PASS Returning undefined with a real iframe unloading FAIL Returning with a real iframe unloading assert_equals: canceled expected true but got false
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html index b415ac2..1f8bb059 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html
@@ -11,43 +11,82 @@ <script> "use strict"; -async_test(t => { +promise_test(t => { let onbeforeunloadHappened = false; window.onbeforeunload = t.step_func(() => { onbeforeunloadHappened = true; return "cancel me"; }); - const listener = t.step_func(e => { + const eventWatcher = new EventWatcher(t, window, "beforeunload"); + const promise = eventWatcher.wait_for("beforeunload").then(e => { assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); assert_false(e.defaultPrevented, "The event must not have been canceled"); window.onbeforeunload = null; - t.done(); }); - window.addEventListener("beforeunload", listener); - window.dispatchEvent(new CustomEvent("beforeunload")); + + return promise; }, "Returning a string must not cancel the event: CustomEvent, non-cancelable"); -async_test(t => { +promise_test(t => { let onbeforeunloadHappened = false; window.onbeforeunload = t.step_func(() => { onbeforeunloadHappened = true; return "cancel me"; }); - const listener = t.step_func(e => { + const eventWatcher = new EventWatcher(t, window, "beforeunload"); + const promise = eventWatcher.wait_for("beforeunload").then(e => { assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); assert_false(e.defaultPrevented, "The event must not have been canceled"); window.onbeforeunload = null; t.done(); }); - window.addEventListener("beforeunload", listener); + window.dispatchEvent(new CustomEvent("beforeunload", { cancelable: true })); + + return promise; +}, "Returning a string must not cancel the event: CustomEvent, cancelable"); + +promise_test(t => { + let onbeforeunloadHappened = false; + window.onbeforeunload = t.step_func(() => { + onbeforeunloadHappened = true; + return false; + }); + + const eventWatcher = new EventWatcher(t, window, "beforeunload"); + const promise = eventWatcher.wait_for("beforeunload").then(e => { + assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); + assert_false(e.defaultPrevented, "The event must not have been canceled"); + window.onbeforeunload = null; + t.done(); + }); window.dispatchEvent(new CustomEvent("beforeunload", { cancelable: true })); -}, "Returning a string must not cancel the event: CustomEvent, cancelable"); + + return promise; +}, "Returning false must cancel the event, because it's coerced to the DOMString \"false\" which does not cancel " + + "CustomEvents: CustomEvent, cancelable"); + +// This test can be removed if we update the DOM Standard to disallow createEvent("BeforeUnloadEvent"). Browser support +// is inconsistent. https://github.com/whatwg/dom/issues/362 +promise_test(t => { + const eventWatcher = new EventWatcher(t, window, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_false(e.defaultPrevented, "The event must not have been canceled"); + window.onbeforeunload = null; + t.done(); + }); + + const ev = document.createEvent("BeforeUnloadEvent"); + ev.initEvent("click", false, true); + window.dispatchEvent(ev); + + return promise; +}, "Returning a string must not cancel the event: BeforeUnloadEvent with type \"click\", cancelable"); const testCases = [ {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html new file mode 100644 index 0000000..75a1772 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html
@@ -0,0 +1,78 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: click events using ErrorEvent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +promise_test(t => { + document.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, document, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + document.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Document, with a synthetic ErrorEvent"); + +promise_test(t => { + window.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + window.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Window, with a synthetic ErrorEvent"); + +promise_test(t => { + const el = document.createElement("script"); + el.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, el, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + el.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on a script element, with a synthetic ErrorEvent"); + +promise_test(t => { + const worker = new Worker("resources/no-op-worker.js"); + worker.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, worker, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + worker.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Worker, with a synthetic ErrorEvent"); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js new file mode 100644 index 0000000..177a99e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js
@@ -0,0 +1,22 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + self.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + self.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on WorkerGlobalScope, with a synthetic ErrorEvent"); + +done();
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-transpose.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-transpose.html new file mode 100644 index 0000000..0f617a0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-transpose.html
@@ -0,0 +1,29 @@ +<title>InputEvent: macOS Transpose</title> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<div id="editable" contenteditable></div> +<script> +test(() => { + assert_not_equals(window.testRunner, undefined, 'This test requires testRunner.'); + + let eventRecorder = ''; + document.addEventListener('beforeinput', event => { + eventRecorder += `beforeinput-${event.inputType}-${event.data}-`; + }); + document.addEventListener('input', event => { + eventRecorder += `input-${event.inputType}`; + }); + + const editable = document.getElementById('editable'); + editable.innerHTML = 'abc'; + editable.focus(); + const selection = window.getSelection(); + selection.collapse(editable, 1); // End of first line. + + // Test Transpose. + eventRecorder = ''; + testRunner.execCommand('transpose'); + assert_equals(editable.innerHTML, 'acb'); + assert_equals(eventRecorder, 'beforeinput-insertTranspose-cb-input-insertTranspose'); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-navigation.html b/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-navigation.html index 35ba19e8..4052d5b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-navigation.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-navigation.html
@@ -24,7 +24,7 @@ function test() { - for (var message of InspectorTest.mainTarget.consoleModel.messages()) { + for (var message of SDK.consoleModel.messages()) { var args = (message.parameters || []).map((arg) => arg.type); InspectorTest.addResult("Message: \"" + message.messageText + "\", arguments: [" + args.join(", ") + "]"); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-remove.html b/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-remove.html index b17cf21e..fb74a8a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-remove.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-enabled/console-clear-arguments-on-frame-remove.html
@@ -31,7 +31,7 @@ function test() { - for (var message of InspectorTest.mainTarget.consoleModel.messages()) { + for (var message of SDK.consoleModel.messages()) { var args = (message.parameters || []).map((arg) => arg.type); InspectorTest.addResult("Message: \"" + message.messageText + "\", arguments: [" + args.join(", ") + "]"); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/console/console-links-on-messages-before-inspection.html b/third_party/WebKit/LayoutTests/http/tests/inspector/console/console-links-on-messages-before-inspection.html index 5eb8f34..390ee4d0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/console/console-links-on-messages-before-inspection.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/console/console-links-on-messages-before-inspection.html
@@ -16,7 +16,7 @@ var mainTarget = SDK.targetManager.mainTarget(); var debuggerModel = SDK.DebuggerModel.fromTarget(mainTarget); var message = new SDK.ConsoleMessage(mainTarget, SDK.ConsoleMessage.MessageSource.JS, SDK.ConsoleMessage.MessageLevel.Info, "hello?", null, "http://127.0.0.1:8000/inspector/resources/source2.js"); - mainTarget.consoleModel.addMessage(message); + SDK.consoleModel.addMessage(message); debuggerModel.addEventListener(SDK.DebuggerModel.Events.ParsedScriptSource, onScriptAdded); InspectorTest.dumpConsoleMessages();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js index 7fe4492..b7a4b9c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -971,7 +971,6 @@ InspectorTest.RuntimeAgent = target.runtimeAgent(); InspectorTest.TargetAgent = target.targetAgent(); - InspectorTest.consoleModel = target.consoleModel; InspectorTest.networkManager = SDK.NetworkManager.fromTarget(target); InspectorTest.securityOriginManager = SDK.SecurityOriginManager.fromTarget(target); InspectorTest.resourceTreeModel = SDK.ResourceTreeModel.fromTarget(target); @@ -988,6 +987,7 @@ InspectorTest.serviceWorkerManager = target.model(SDK.ServiceWorkerManager); InspectorTest.tracingManager = target.model(SDK.TracingManager); InspectorTest.mainTarget = target; + InspectorTest.consoleModel = SDK.consoleModel; }, targetRemoved: function(target) { }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/user-agent-override.html b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/user-agent-override.html index 355837e..61d0ab08 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/user-agent-override.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/service-workers/user-agent-override.html
@@ -30,13 +30,13 @@ function waitForConsoleMessage(regex) { return new Promise(function(resolve) { - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, sniff); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, sniff); function sniff(e) { if (e.data && regex.test(e.data.messageText)) { resolve(e.data); - SDK.multitargetConsoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, sniff); + SDK.consoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, sniff); } } });
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-preserve-log.html b/third_party/WebKit/LayoutTests/inspector/console/console-preserve-log.html index e01384fa..5e9cb3d 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/console-preserve-log.html +++ b/third_party/WebKit/LayoutTests/inspector/console/console-preserve-log.html
@@ -5,7 +5,7 @@ <script> function test() { - InspectorTest.consoleModel.addMessage(new SDK.ConsoleMessage(InspectorTest.consoleModel.target(), SDK.ConsoleMessage.MessageSource.Other, SDK.ConsoleMessage.MessageLevel.Info, "PASS")); + InspectorTest.consoleModel.addMessage(new SDK.ConsoleMessage(InspectorTest.mainTarget, SDK.ConsoleMessage.MessageSource.Other, SDK.ConsoleMessage.MessageLevel.Info, "PASS")); Common.settingForTest("preserveConsoleLog").set(true); InspectorTest.reloadPage(function() { InspectorTest.dumpConsoleMessages();
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-revoke-error-in-worker.html b/third_party/WebKit/LayoutTests/inspector/console/console-revoke-error-in-worker.html index 50fcf62..341c25c 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/console-revoke-error-in-worker.html +++ b/third_party/WebKit/LayoutTests/inspector/console/console-revoke-error-in-worker.html
@@ -18,8 +18,8 @@ function test() { - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, InspectorTest.wrapListener(messageAdded)); - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageUpdated, InspectorTest.wrapListener(messageUpdated)); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, InspectorTest.wrapListener(messageAdded)); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageUpdated, InspectorTest.wrapListener(messageUpdated)); InspectorTest.addResult("Creating worker with promise"); InspectorTest.evaluateInPageWithTimeout("createPromise()");
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-timestamp.html b/third_party/WebKit/LayoutTests/inspector/console/console-timestamp.html index 634b5d0..1bc866e5 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/console-timestamp.html +++ b/third_party/WebKit/LayoutTests/inspector/console/console-timestamp.html
@@ -14,7 +14,7 @@ function addMessageWithFixedTimestamp(messageText, timestamp) { var message = new SDK.ConsoleMessage( - InspectorTest.consoleModel.target(), + InspectorTest.mainTarget, SDK.ConsoleMessage.MessageSource.Other, // source SDK.ConsoleMessage.MessageLevel.Info, // level messageText,
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html index f024d78..4945678 100644 --- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html +++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
@@ -64,11 +64,11 @@ InspectorTest.disableConsoleViewport(); InspectorTest.evaluateInPage("logMessage()"); var wrappedConsoleMessageAdded = InspectorTest.safeWrap(consoleMessageAdded); - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, wrappedConsoleMessageAdded); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, wrappedConsoleMessageAdded); function consoleMessageAdded() { - SDK.multitargetConsoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, wrappedConsoleMessageAdded); + SDK.consoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, wrappedConsoleMessageAdded); Console.ConsoleView.instance()._viewportThrottler.flush(); InspectorTest.deprecatedRunAfterPendingDispatches(clickOnMessage) }
diff --git a/third_party/WebKit/LayoutTests/inspector/input-event-warning.html b/third_party/WebKit/LayoutTests/inspector/input-event-warning.html index 75df9f9..0822b324 100644 --- a/third_party/WebKit/LayoutTests/inspector/input-event-warning.html +++ b/third_party/WebKit/LayoutTests/inspector/input-event-warning.html
@@ -62,7 +62,7 @@ function test() { - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, InspectorTest.safeWrap(onConsoleMessage)); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, InspectorTest.safeWrap(onConsoleMessage)); step1(); function step1()
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition.html index df0c230c..59e642c 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-function-definition.html
@@ -40,7 +40,7 @@ function testDumpFunctionDefinition(next) { InspectorTest.addSniffer(ObjectUI.ObjectPropertiesSection, "formatObjectAsFunction", onConsoleMessagesReceived); - SDK.ConsoleModel.evaluateCommandInConsole(UI.context.flavor(SDK.ExecutionContext), "jumpToMe"); + SDK.consoleModel.evaluateCommandInConsole(UI.context.flavor(SDK.ExecutionContext), "jumpToMe"); function onConsoleMessagesReceived() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt index b0f4608..add010f 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt
@@ -1,27 +1,6 @@ Tests js cpu profile in timeline. Main Thread -EvaluateScript Properties: -{ - data : { - } - endTime : <number> - startTime : <number> - type : "EvaluateScript" -} DedicatedWorker Thread DedicatedWorker Thread -EvaluateScript Properties: -{ - data : { - columnNumber : <number> - frame : <string> - lineNumber : <number> - url : .../inspector/tracing/resources/worker.js - } - endTime : <number> - frameId : <string> - startTime : <number> - type : "EvaluateScript" -}
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html b/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html index 871225a7..caa7a8e4 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html +++ b/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html
@@ -67,32 +67,28 @@ { var mainThread = { name: "Main Thread", events: InspectorTest.timelineModel()._mainThreadEvents }; processThread(new Set(["startSecondWorker", "worker2.onmessage"]), mainThread); - InspectorTest.timelineModel()._virtualThreads.forEach(function(thread) - { + for (var thread of InspectorTest.timelineModel()._virtualThreads) { if (!thread.isWorker()) - return; - processThread(new Set(["onmessage"]), thread); - }); + continue; + processThread(new Set(["Function Call"]), thread); + } InspectorTest.completeTest(); } - function processThread(expectedFunctions, thread) + function processThread(expectedEvents, thread) { InspectorTest.addResult(thread.name); - var missingFunctions = thread.events.reduce(processEvent, expectedFunctions); - if (missingFunctions.size) { - InspectorTest.addResult("FAIL: missing functions:"); - missingFunctions.forEach(InspectorTest.addResult); + var missingEvents = thread.events.reduce(processEvent, expectedEvents); + if (missingEvents.size) { + InspectorTest.addResult("FAIL: missing events:"); + missingEvents.forEach(InspectorTest.addResult); } } - function processEvent(expectedFunctions, event) + function processEvent(expectedEvents, event) { - if (event.name === TimelineModel.TimelineModel.RecordType.EvaluateScript) - InspectorTest.printTraceEventProperties(event); - if (event.name === TimelineModel.TimelineModel.RecordType.JSFrame) - expectedFunctions.delete(event.args.data.functionName); - return expectedFunctions; + expectedEvents.delete(Timeline.TimelineUIUtils.eventTitle(event)); + return expectedEvents; } }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index 640e9505..93b2dc5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 284.00 scrollHeight 842 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 284.00 scrollHeight 842 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-242) size 559x842 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-242) size 559x842 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 558.97x842 LayoutBlockFlow (anonymous) at (0,0) size 558.97x20 LayoutText {#text} at (0,0) size 559x19
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index e4d13bce2..504b9d26 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 278.00 scrollHeight 836 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 278.00 scrollHeight 836 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-236) size 570x836 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-236) size 570x836 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 570.41x836 LayoutBlockFlow (anonymous) at (0,0) size 570.41x18 LayoutText {#text} at (0,0) size 571x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index 9faa65ef..f8ebb28 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 278.00 scrollHeight 836 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 278.00 scrollHeight 836 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-236) size 570x836 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-236) size 570x836 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 570.41x836 LayoutBlockFlow (anonymous) at (0,0) size 570.41x18 LayoutText {#text} at (0,0) size 571x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index cbf97bd..9e0ca43 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 278.00 scrollHeight 836 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 278.00 scrollHeight 836 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-236) size 570x836 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-236) size 570x836 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 570.41x836 LayoutBlockFlow (anonymous) at (0,0) size 570.41x18 LayoutText {#text} at (0,0) size 571x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index 9faa65ef..f8ebb28 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 278.00 scrollHeight 836 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 278.00 scrollHeight 836 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-236) size 570x836 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-236) size 570x836 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 570.41x836 LayoutBlockFlow (anonymous) at (0,0) size 570.41x18 LayoutText {#text} at (0,0) size 571x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index bb84c3c..2acc770 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 278.00 scrollHeight 836 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 278.00 scrollHeight 836 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-236) size 570x836 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-236) size 570x836 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 570.41x836 LayoutBlockFlow (anonymous) at (0,0) size 570.41x18 LayoutText {#text} at (0,0) size 571x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_position-table-cell-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_position-table-cell-expected.png index f0fd7ff6..5750e958 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_position-table-cell-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_position-table-cell-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt index d652bc4..15e5c4c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/overflow/scroll-nested-positioned-layer-in-overflow-expected.txt
@@ -3,9 +3,9 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 -layer at (0,42) size 800x558 scrollY 282.00 scrollHeight 840 +layer at (0,42) size 800x558 clip at (0,42) size 785x558 scrollY 282.00 scrollHeight 840 LayoutBlockFlow (positioned) {DIV} at (0,42) size 800x558 -layer at (0,-240) size 571x840 backgroundClip at (0,42) size 800x558 clip at (0,42) size 800x558 +layer at (0,-240) size 571x840 backgroundClip at (0,42) size 785x558 clip at (0,42) size 785x558 LayoutBlockFlow (positioned) {DIV} at (0,0) size 571.28x840 LayoutBlockFlow (anonymous) at (0,0) size 571.28x18 LayoutText {#text} at (0,0) size 572x17
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt index 326a19b..ff9be7c 100644 --- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
@@ -15,7 +15,7 @@ }, { "name": "Scrolling Layer", - "bounds": [300, 300], + "bounds": [285, 285], "shouldFlattenTransform": false }, {
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/permissions-attribute-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/permissions-attribute-expected.txt deleted file mode 100644 index ee94514..0000000 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/permissions-attribute-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests that the permissions attribute is not exposed for stable - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt index 639df5f..9f75dde 100644 --- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -567,7 +567,6 @@ property marginHeight property marginWidth property name - property permissions property referrerPolicy property sandbox property scrolling
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 5718059..597f6a0 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2625,7 +2625,6 @@ getter marginHeight getter marginWidth getter name - getter permissions getter referrerPolicy getter sandbox getter scrolling @@ -2644,7 +2643,6 @@ setter marginHeight setter marginWidth setter name - setter permissions setter referrerPolicy setter sandbox setter scrolling
diff --git a/third_party/WebKit/LayoutTests/webexposed/permissions-attribute-expected.txt b/third_party/WebKit/LayoutTests/webexposed/permissions-attribute-expected.txt index e59c8077..ee94514 100644 --- a/third_party/WebKit/LayoutTests/webexposed/permissions-attribute-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/permissions-attribute-expected.txt
@@ -1,4 +1,3 @@ -CONSOLE ERROR: line 7: Error while parsing the 'permissions' attribute: 'abcdefg' is an invalid permissions flag. Tests that the permissions attribute is not exposed for stable On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/Source/bindings/bindings.gni b/third_party/WebKit/Source/bindings/bindings.gni index 057f211..8d42eea 100644 --- a/third_party/WebKit/Source/bindings/bindings.gni +++ b/third_party/WebKit/Source/bindings/bindings.gni
@@ -232,6 +232,7 @@ bindings_unittest_files = get_path_info([ "core/v8/DocumentWriteEvaluatorTest.cpp", + "core/v8/DOMWrapperWorldTest.cpp", "core/v8/IDLTypesTest.cpp", "core/v8/NativeValueTraitsImplTest.cpp", "core/v8/NativeValueTraitsTest.cpp",
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h b/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h index f1825983..03d9030 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h +++ b/third_party/WebKit/Source/bindings/core/v8/DOMDataStore.h
@@ -156,7 +156,7 @@ // be in the main world). static bool canUseMainWorldWrapper() { return !WTF::mayNotBeMainThread() && - !DOMWrapperWorld::nonMainWorldsInMainThread(); + !DOMWrapperWorld::nonMainWorldsExistInMainThread(); } static bool holderContainsWrapper(v8::Local<v8::Object> holder,
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp index 24b1935d..39f9f840 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp
@@ -84,19 +84,17 @@ unsigned DOMWrapperWorld::s_numberOfNonMainWorldsInMainThread = 0; using WorldMap = HashMap<int, DOMWrapperWorld*>; - -static WorldMap& isolatedWorldMap() { - DCHECK(isMainThread()); - DEFINE_STATIC_LOCAL(WorldMap, map, ()); - return map; -} - static WorldMap& worldMap() { DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<WorldMap>, map, new ThreadSpecific<WorldMap>); return *map; } +static bool isIsolatedWorldId(int worldId) { + return DOMWrapperWorld::MainWorldId < worldId && + worldId < DOMWrapperWorld::IsolatedWorldIdLimit; +} + PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::create(v8::Isolate* isolate, WorldType worldType) { DCHECK_NE(WorldType::Isolated, worldType); @@ -111,30 +109,23 @@ m_worldId(worldId), m_domDataStore( WTF::wrapUnique(new DOMDataStore(isolate, isMainWorld()))) { - switch (worldType) { + switch (m_worldType) { case WorldType::Main: - // MainWorld is managed separately from worldMap() and isolatedWorldMap(). - // See mainWorld(). + // MainWorld is managed separately from worldMap(). See mainWorld(). break; - case WorldType::Isolated: { - DCHECK(isMainThread()); - WorldMap& map = isolatedWorldMap(); - DCHECK(!map.contains(worldId)); - map.insert(worldId, this); - break; - } + case WorldType::Isolated: case WorldType::GarbageCollector: case WorldType::RegExp: case WorldType::Testing: case WorldType::Worker: { WorldMap& map = worldMap(); - DCHECK(!map.contains(worldId)); - map.insert(worldId, this); + DCHECK(!map.contains(m_worldId)); + map.insert(m_worldId, this); + if (isMainThread()) + s_numberOfNonMainWorldsInMainThread++; break; } } - if (worldId != WorldId::MainWorldId && isMainThread()) - s_numberOfNonMainWorldsInMainThread++; } DOMWrapperWorld& DOMWrapperWorld::mainWorld() { @@ -147,25 +138,33 @@ PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::fromWorldId(v8::Isolate* isolate, int worldId) { - if (worldId == MainWorldId) + // TODO(nhiroki): The current impl creates a new main/isolated world for + // |worldId| if it doesn't exist. We should stop it and instead return nullptr + // in the case. + if (worldId == WorldId::MainWorldId) return &mainWorld(); - return ensureIsolatedWorld(isolate, worldId); + if (isIsolatedWorldId(worldId)) + return ensureIsolatedWorld(isolate, worldId); + + WorldMap& map = worldMap(); + auto it = map.find(worldId); + if (it != map.end()) + return it->value; + return nullptr; } -void DOMWrapperWorld::allWorldsInMainThread( +void DOMWrapperWorld::allWorldsInCurrentThread( Vector<RefPtr<DOMWrapperWorld>>& worlds) { - ASSERT(isMainThread()); - worlds.push_back(&mainWorld()); + if (isMainThread()) + worlds.push_back(&mainWorld()); for (DOMWrapperWorld* world : worldMap().values()) worlds.push_back(world); - for (DOMWrapperWorld* world : isolatedWorldMap().values()) - worlds.push_back(world); } void DOMWrapperWorld::markWrappersInAllWorlds( ScriptWrappable* scriptWrappable, const ScriptWrappableVisitor* visitor) { - // Marking for worlds other than the main world and the isolated worlds. + // Marking for worlds other than the main world. DCHECK(ThreadState::current()->isolate()); for (DOMWrapperWorld* world : worldMap().values()) { DOMDataStore& dataStore = world->domDataStore(); @@ -173,66 +172,39 @@ dataStore.markWrapper(scriptWrappable); } - // The main world and isolated worlds should exist only on the main thread. - if (!isMainThread()) - return; - // Marking for the main world. - scriptWrappable->markWrapper(visitor); - - // Marking for the isolated worlds. - WorldMap& isolatedWorlds = isolatedWorldMap(); - for (auto& world : isolatedWorlds.values()) { - DOMDataStore& dataStore = world->domDataStore(); - if (dataStore.containsWrapper(scriptWrappable)) - dataStore.markWrapper(scriptWrappable); - } + if (isMainThread()) + scriptWrappable->markWrapper(visitor); } DOMWrapperWorld::~DOMWrapperWorld() { ASSERT(!isMainWorld()); - - dispose(); - if (isMainThread()) s_numberOfNonMainWorldsInMainThread--; - if (!isIsolatedWorld()) - return; - - WorldMap& map = isolatedWorldMap(); - WorldMap::iterator it = map.find(m_worldId); - if (it == map.end()) { - ASSERT_NOT_REACHED(); - return; - } - ASSERT(it->value == this); - - map.remove(it); + // WorkerWorld should be disposed of before the dtor. + if (!isWorkerWorld()) + dispose(); + DCHECK(!worldMap().contains(m_worldId)); } void DOMWrapperWorld::dispose() { m_domObjectHolders.clear(); m_domDataStore.reset(); + DCHECK(worldMap().contains(m_worldId)); worldMap().remove(m_worldId); } -#if DCHECK_IS_ON() -static bool isIsolatedWorldId(int worldId) { - return DOMWrapperWorld::MainWorldId < worldId && - worldId < DOMWrapperWorld::IsolatedWorldIdLimit; -} -#endif - PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::ensureIsolatedWorld( v8::Isolate* isolate, int worldId) { ASSERT(isIsolatedWorldId(worldId)); - WorldMap& map = isolatedWorldMap(); + WorldMap& map = worldMap(); auto it = map.find(worldId); if (it != map.end()) { RefPtr<DOMWrapperWorld> world = it->value; + DCHECK(world->isIsolatedWorld()); DCHECK_EQ(worldId, world->worldId()); return world.release(); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h index d4821bd4..7dba1dd 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h
@@ -84,10 +84,13 @@ ~DOMWrapperWorld(); void dispose(); - static bool nonMainWorldsInMainThread() { + // Called from performance-sensitive functions, so we should keep this simple + // and fast as much as possible. + static bool nonMainWorldsExistInMainThread() { return s_numberOfNonMainWorldsInMainThread; } - static void allWorldsInMainThread(Vector<RefPtr<DOMWrapperWorld>>& worlds); + + static void allWorldsInCurrentThread(Vector<RefPtr<DOMWrapperWorld>>& worlds); static void markWrappersInAllWorlds(ScriptWrappable*, const ScriptWrappableVisitor*); @@ -99,7 +102,6 @@ return world(isolate->GetCurrentContext()); } - static DOMWrapperWorld*& workerWorld(); static DOMWrapperWorld& mainWorld(); static PassRefPtr<DOMWrapperWorld> fromWorldId(v8::Isolate*, int worldId);
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp new file mode 100644 index 0000000..3206ef0 --- /dev/null +++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp
@@ -0,0 +1,161 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "bindings/core/v8/DOMWrapperWorld.h" + +#include "bindings/core/v8/V8BindingForTesting.h" +#include "bindings/core/v8/V8Initializer.h" +#include "bindings/core/v8/V8PerIsolateData.h" +#include "core/workers/WorkerBackingThread.h" +#include "platform/CrossThreadFunctional.h" +#include "platform/WebTaskRunner.h" +#include "platform/WebThreadSupportingGC.h" +#include "platform/testing/UnitTestHelpers.h" +#include "public/platform/Platform.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace { + +Vector<RefPtr<DOMWrapperWorld>> createIsolatedWorlds(v8::Isolate* isolate) { + Vector<RefPtr<DOMWrapperWorld>> worlds; + worlds.push_back(DOMWrapperWorld::ensureIsolatedWorld( + isolate, DOMWrapperWorld::WorldId::MainWorldId + 1)); + worlds.push_back(DOMWrapperWorld::ensureIsolatedWorld( + isolate, DOMWrapperWorld::WorldId::IsolatedWorldIdLimit - 1)); + EXPECT_TRUE(worlds[0]->isIsolatedWorld()); + EXPECT_TRUE(worlds[1]->isIsolatedWorld()); + EXPECT_EQ(worlds[0], + DOMWrapperWorld::fromWorldId(isolate, worlds[0]->worldId())); + EXPECT_EQ(worlds[1], + DOMWrapperWorld::fromWorldId(isolate, worlds[1]->worldId())); + return worlds; +} + +Vector<RefPtr<DOMWrapperWorld>> createWorlds(v8::Isolate* isolate) { + Vector<RefPtr<DOMWrapperWorld>> worlds; + worlds.push_back( + DOMWrapperWorld::create(isolate, DOMWrapperWorld::WorldType::Worker)); + worlds.push_back( + DOMWrapperWorld::create(isolate, DOMWrapperWorld::WorldType::Worker)); + worlds.push_back(DOMWrapperWorld::create( + isolate, DOMWrapperWorld::WorldType::GarbageCollector)); + EXPECT_TRUE(worlds[0]->isWorkerWorld()); + EXPECT_TRUE(worlds[1]->isWorkerWorld()); + EXPECT_FALSE(worlds[2]->isWorkerWorld()); + + // World ids should be unique. + HashSet<int> worldIds; + EXPECT_TRUE(worldIds.insert(worlds[0]->worldId()).isNewEntry); + EXPECT_TRUE(worldIds.insert(worlds[1]->worldId()).isNewEntry); + EXPECT_TRUE(worldIds.insert(worlds[2]->worldId()).isNewEntry); + EXPECT_EQ(worlds[0], + DOMWrapperWorld::fromWorldId(isolate, worlds[0]->worldId())); + EXPECT_EQ(worlds[1], + DOMWrapperWorld::fromWorldId(isolate, worlds[1]->worldId())); + EXPECT_EQ(worlds[2], + DOMWrapperWorld::fromWorldId(isolate, worlds[2]->worldId())); + + return worlds; +} + +void workerThreadFunc(WorkerBackingThread* thread, + RefPtr<WebTaskRunner> mainThreadTaskRunner) { + thread->initialize(); + + // Worlds on the main thread should not be visible from the worker thread. + Vector<RefPtr<DOMWrapperWorld>> retrievedWorlds; + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_TRUE(retrievedWorlds.isEmpty()); + + // Create worlds on the worker thread and verify them. + Vector<RefPtr<DOMWrapperWorld>> worlds = createWorlds(thread->isolate()); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(worlds.size(), retrievedWorlds.size()); + retrievedWorlds.clear(); + + // Dispose of the last world. + worlds.pop_back(); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(worlds.size(), retrievedWorlds.size()); + + // Dispose of remaining worlds. + for (RefPtr<DOMWrapperWorld>& world : worlds) { + if (world->isWorkerWorld()) + world->dispose(); + } + worlds.clear(); + + thread->shutdown(); + mainThreadTaskRunner->postTask(BLINK_FROM_HERE, + crossThreadBind(&testing::exitRunLoop)); +} + +TEST(DOMWrapperWorldTest, Basic) { + V8TestingScope scope; + + // Create the main world and verify it. + DOMWrapperWorld& mainWorld = DOMWrapperWorld::mainWorld(); + EXPECT_TRUE(mainWorld.isMainWorld()); + EXPECT_FALSE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + Vector<RefPtr<DOMWrapperWorld>> retrievedWorlds; + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(1u, retrievedWorlds.size()); + EXPECT_TRUE(retrievedWorlds[0]->isMainWorld()); + EXPECT_EQ(&mainWorld, + DOMWrapperWorld::fromWorldId(scope.isolate(), mainWorld.worldId())); + retrievedWorlds.clear(); + + // Create isolated worlds and verify them. + Vector<RefPtr<DOMWrapperWorld>> isolatedWorlds = + createIsolatedWorlds(scope.isolate()); + EXPECT_TRUE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(isolatedWorlds.size() + 1, retrievedWorlds.size()); + + // Create other worlds and verify them. + Vector<RefPtr<DOMWrapperWorld>> worlds = createWorlds(scope.isolate()); + EXPECT_TRUE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + retrievedWorlds.clear(); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(isolatedWorlds.size() + worlds.size() + 1, retrievedWorlds.size()); + retrievedWorlds.clear(); + + // Start a worker thread and create worlds on that. + std::unique_ptr<WorkerBackingThread> thread = + WorkerBackingThread::create("DOMWrapperWorld test thread"); + RefPtr<WebTaskRunner> mainThreadTaskRunner = + Platform::current()->currentThread()->getWebTaskRunner(); + thread->backingThread().postTask( + BLINK_FROM_HERE, + crossThreadBind(&workerThreadFunc, crossThreadUnretained(thread.get()), + std::move(mainThreadTaskRunner))); + testing::enterRunLoop(); + + // Worlds on the worker thread should not be visible from the main thread. + EXPECT_TRUE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(isolatedWorlds.size() + worlds.size() + 1, retrievedWorlds.size()); + retrievedWorlds.clear(); + + // Dispose of the isolated worlds. + isolatedWorlds.clear(); + EXPECT_TRUE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(worlds.size() + 1, retrievedWorlds.size()); + retrievedWorlds.clear(); + + // Dispose of the other worlds. + for (RefPtr<DOMWrapperWorld>& world : worlds) { + if (world->isWorkerWorld()) + world->dispose(); + } + worlds.clear(); + EXPECT_FALSE(DOMWrapperWorld::nonMainWorldsExistInMainThread()); + DOMWrapperWorld::allWorldsInCurrentThread(retrievedWorlds); + EXPECT_EQ(1u, retrievedWorlds.size()); +} + +} // namespace +} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp index ee223db..bf7ba0c 100644 --- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
@@ -175,18 +175,10 @@ v8::Isolate* isolate, DOMArrayBuffer* object, Vector<v8::Local<v8::ArrayBuffer>, 4>& buffers) { - if (isMainThread()) { - Vector<RefPtr<DOMWrapperWorld>> worlds; - DOMWrapperWorld::allWorldsInMainThread(worlds); - for (size_t i = 0; i < worlds.size(); i++) { - v8::Local<v8::Object> wrapper = - worlds[i]->domDataStore().get(object, isolate); - if (!wrapper.IsEmpty()) - buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper)); - } - } else { - v8::Local<v8::Object> wrapper = - DOMWrapperWorld::current(isolate).domDataStore().get(object, isolate); + Vector<RefPtr<DOMWrapperWorld>> worlds; + DOMWrapperWorld::allWorldsInCurrentThread(worlds); + for (const auto& world : worlds) { + v8::Local<v8::Object> wrapper = world->domDataStore().get(object, isolate); if (!wrapper.IsEmpty()) buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper)); }
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index 6d9dd48..c14d3f1 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1237,7 +1237,6 @@ "html/HTMLEmbedElementTest.cpp", "html/HTMLFormControlElementTest.cpp", "html/HTMLIFrameElementAllowTest.cpp", - "html/HTMLIFrameElementPermissionsTest.cpp", "html/HTMLIFrameElementTest.cpp", "html/HTMLImageElementTest.cpp", "html/HTMLInputElementTest.cpp",
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp index 3a22738..a45a7e3 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -306,7 +306,7 @@ for (bool& flag : cancelRunningAnimationFlags) flag = true; - if (animationData && style.display() != EDisplay::None) { + if (animationData && style.display() != EDisplay::kNone) { const Vector<AtomicString>& nameList = animationData->nameList(); for (size_t i = 0; i < nameList.size(); ++i) { AtomicString name = nameList[i]; @@ -859,7 +859,7 @@ HashSet<PropertyHandle> listedProperties; bool anyTransitionHadTransitionAll = false; const LayoutObject* layoutObject = animatingElement->layoutObject(); - if (!animationStyleRecalc && style.display() != EDisplay::None && + if (!animationStyleRecalc && style.display() != EDisplay::kNone && layoutObject && layoutObject->style() && transitionData) { TransitionUpdateState state = { update, animatingElement, *layoutObject->style(),
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h index 842f8b6..f95be0b 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -1066,73 +1066,73 @@ inline CSSIdentifierValue::CSSIdentifierValue(EDisplay e) : CSSValue(IdentifierClass) { switch (e) { - case EDisplay::Inline: + case EDisplay::kInline: m_valueID = CSSValueInline; break; - case EDisplay::Block: + case EDisplay::kBlock: m_valueID = CSSValueBlock; break; - case EDisplay::ListItem: + case EDisplay::kListItem: m_valueID = CSSValueListItem; break; - case EDisplay::InlineBlock: + case EDisplay::kInlineBlock: m_valueID = CSSValueInlineBlock; break; - case EDisplay::Table: + case EDisplay::kTable: m_valueID = CSSValueTable; break; - case EDisplay::InlineTable: + case EDisplay::kInlineTable: m_valueID = CSSValueInlineTable; break; - case EDisplay::TableRowGroup: + case EDisplay::kTableRowGroup: m_valueID = CSSValueTableRowGroup; break; - case EDisplay::TableHeaderGroup: + case EDisplay::kTableHeaderGroup: m_valueID = CSSValueTableHeaderGroup; break; - case EDisplay::TableFooterGroup: + case EDisplay::kTableFooterGroup: m_valueID = CSSValueTableFooterGroup; break; - case EDisplay::TableRow: + case EDisplay::kTableRow: m_valueID = CSSValueTableRow; break; - case EDisplay::TableColumnGroup: + case EDisplay::kTableColumnGroup: m_valueID = CSSValueTableColumnGroup; break; - case EDisplay::TableColumn: + case EDisplay::kTableColumn: m_valueID = CSSValueTableColumn; break; - case EDisplay::TableCell: + case EDisplay::kTableCell: m_valueID = CSSValueTableCell; break; - case EDisplay::TableCaption: + case EDisplay::kTableCaption: m_valueID = CSSValueTableCaption; break; - case EDisplay::WebkitBox: + case EDisplay::kWebkitBox: m_valueID = CSSValueWebkitBox; break; - case EDisplay::WebkitInlineBox: + case EDisplay::kWebkitInlineBox: m_valueID = CSSValueWebkitInlineBox; break; - case EDisplay::Flex: + case EDisplay::kFlex: m_valueID = CSSValueFlex; break; - case EDisplay::InlineFlex: + case EDisplay::kInlineFlex: m_valueID = CSSValueInlineFlex; break; - case EDisplay::Grid: + case EDisplay::kGrid: m_valueID = CSSValueGrid; break; - case EDisplay::InlineGrid: + case EDisplay::kInlineGrid: m_valueID = CSSValueInlineGrid; break; - case EDisplay::Contents: + case EDisplay::kContents: m_valueID = CSSValueContents; break; - case EDisplay::FlowRoot: + case EDisplay::kFlowRoot: m_valueID = CSSValueFlowRoot; break; - case EDisplay::None: + case EDisplay::kNone: m_valueID = CSSValueNone; break; } @@ -1142,57 +1142,57 @@ inline EDisplay CSSIdentifierValue::convertTo() const { switch (m_valueID) { case CSSValueInline: - return EDisplay::Inline; + return EDisplay::kInline; case CSSValueBlock: - return EDisplay::Block; + return EDisplay::kBlock; case CSSValueListItem: - return EDisplay::ListItem; + return EDisplay::kListItem; case CSSValueInlineBlock: - return EDisplay::InlineBlock; + return EDisplay::kInlineBlock; case CSSValueTable: - return EDisplay::Table; + return EDisplay::kTable; case CSSValueInlineTable: - return EDisplay::InlineTable; + return EDisplay::kInlineTable; case CSSValueTableRowGroup: - return EDisplay::TableRowGroup; + return EDisplay::kTableRowGroup; case CSSValueTableHeaderGroup: - return EDisplay::TableHeaderGroup; + return EDisplay::kTableHeaderGroup; case CSSValueTableFooterGroup: - return EDisplay::TableFooterGroup; + return EDisplay::kTableFooterGroup; case CSSValueTableRow: - return EDisplay::TableRow; + return EDisplay::kTableRow; case CSSValueTableColumnGroup: - return EDisplay::TableColumnGroup; + return EDisplay::kTableColumnGroup; case CSSValueTableColumn: - return EDisplay::TableColumn; + return EDisplay::kTableColumn; case CSSValueTableCell: - return EDisplay::TableCell; + return EDisplay::kTableCell; case CSSValueTableCaption: - return EDisplay::TableCaption; + return EDisplay::kTableCaption; case CSSValueWebkitBox: - return EDisplay::WebkitBox; + return EDisplay::kWebkitBox; case CSSValueWebkitInlineBox: - return EDisplay::WebkitInlineBox; + return EDisplay::kWebkitInlineBox; case CSSValueFlex: case CSSValueWebkitFlex: - return EDisplay::Flex; + return EDisplay::kFlex; case CSSValueInlineFlex: case CSSValueWebkitInlineFlex: - return EDisplay::InlineFlex; + return EDisplay::kInlineFlex; case CSSValueGrid: - return EDisplay::Grid; + return EDisplay::kGrid; case CSSValueInlineGrid: - return EDisplay::InlineGrid; + return EDisplay::kInlineGrid; case CSSValueContents: - return EDisplay::Contents; + return EDisplay::kContents; case CSSValueFlowRoot: - return EDisplay::FlowRoot; + return EDisplay::kFlowRoot; case CSSValueNone: - return EDisplay::None; + return EDisplay::kNone; break; default: NOTREACHED(); - return EDisplay::None; + return EDisplay::kNone; } }
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 6227c6d6..e21383e9 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -2368,7 +2368,7 @@ return CSSPrimitiveValue::create(style.order(), CSSPrimitiveValue::UnitType::Number); case CSSPropertyFloat: - if (style.display() != EDisplay::None && style.hasOutOfFlowPosition()) + if (style.display() != EDisplay::kNone && style.hasOutOfFlowPosition()) return CSSIdentifierValue::create(CSSValueNone); return CSSIdentifierValue::create(style.floating()); case CSSPropertyFont: @@ -2582,7 +2582,7 @@ if (marginRight.isPercentOrCalc()) { // LayoutBox gives a marginRight() that is the distance between the // right-edge of the child box and the right-edge of the containing box, - // when display == EDisplay::Block. Let's calculate the absolute value + // when display == EDisplay::kBlock. Let's calculate the absolute value // of the specified margin-right % instead of relying on LayoutBox's // marginRight() value. value = minimumValueForLength(
diff --git a/third_party/WebKit/Source/core/css/properties/README.md b/third_party/WebKit/Source/core/css/properties/README.md new file mode 100644 index 0000000..35fad85 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/README.md
@@ -0,0 +1,52 @@ +# Property APIs + +This directory contains implementations for CSS property APIs, as well as Utils +files containing functions commonly used by the property APIs. + +A CSS property API represents a single CSS property or a group of CSS +properties, and defines the logic for that property or group of properties. + +Examples: + +* A single property API: the `CSSPropertyAPILineHeight` class is used only by + the `line-height` property +* A group of properties that share logic: the `CSSPropertyAPIImage` class + is shared by the `border-image-source` and `list-style-image` properties. + +Status (March 16 2017): Eventually, all logic pertaining to a single property +should be found only within its CSS property API. Currently, the code base is in +a transitional state and property specific logic is still scattered around the +code base. See Project Ribbon +[tracking bug](https://bugs.chromium.org/p/chromium/issues/detail?id=545324) and +[design doc](https://docs.google.com/document/d/1ywjUTmnxF5FXlpUTuLpint0w4TdSsjJzdWJqmhNzlss/edit#heading=h.1ckibme4i78b) +for details of progress. + +## How to add a new property API + +1. Add a .cpp file to this directory named + `CSSPropertyAPI<Property/GroupName>.cpp` +2. Implement the property API in the .cpp file + 1. Add `#include "core/css/properties/CSSPropertyAPI<Property/GroupName>.h"` + (this will be a generated file) + 2. Implement the required methods on the API, e.g. `parseSingleValue` +3. If logic is required by multiple property APIs you may need to create a new + Utils file. +4. Add the new property to `core/css/CSSProperties.json5`. Ensure that you + include the 'api_class' flag and the 'api_methods' flag so that the API + files are generated correctly (see + [CSSProperties.json5](https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/CSSProperties.json5) + for more details) +5. Add new files to BUILD files + 1. Add the new .cpp file to + [core/css/BUILD.gn](https://codesearch.chromium.org/chromium/src/third_party/WebKit/Source/core/css/BUILD.gn) + in the `blink_core_sources` target's `sources` parameter + 2. Add the generated .h file to + [core/BUILD.gn](https://codesearch.chromium.org/chromium/src/third_party/WebKit/Source/core/BUILD.gn) + in the `css_properties` target's `outputs` parameter + +See [this example CL](https://codereview.chromium.org/2735093005), which +converts the existing line-height property to use the CSSPropertyAPI design. +This new line-height property API only implements the parseSingleValue method, +using +[CSSPropertyFontUtils.cpp](https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/properties/CSSPropertyFontUtils.h) +to access shared font logic.
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp index 1e9fa35..24af17b 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
@@ -58,41 +58,41 @@ static EDisplay equivalentBlockDisplay(EDisplay display) { switch (display) { - case EDisplay::Block: - case EDisplay::Table: - case EDisplay::WebkitBox: - case EDisplay::Flex: - case EDisplay::Grid: - case EDisplay::ListItem: - case EDisplay::FlowRoot: + case EDisplay::kBlock: + case EDisplay::kTable: + case EDisplay::kWebkitBox: + case EDisplay::kFlex: + case EDisplay::kGrid: + case EDisplay::kListItem: + case EDisplay::kFlowRoot: return display; - case EDisplay::InlineTable: - return EDisplay::Table; - case EDisplay::WebkitInlineBox: - return EDisplay::WebkitBox; - case EDisplay::InlineFlex: - return EDisplay::Flex; - case EDisplay::InlineGrid: - return EDisplay::Grid; + case EDisplay::kInlineTable: + return EDisplay::kTable; + case EDisplay::kWebkitInlineBox: + return EDisplay::kWebkitBox; + case EDisplay::kInlineFlex: + return EDisplay::kFlex; + case EDisplay::kInlineGrid: + return EDisplay::kGrid; - case EDisplay::Contents: - case EDisplay::Inline: - case EDisplay::InlineBlock: - case EDisplay::TableRowGroup: - case EDisplay::TableHeaderGroup: - case EDisplay::TableFooterGroup: - case EDisplay::TableRow: - case EDisplay::TableColumnGroup: - case EDisplay::TableColumn: - case EDisplay::TableCell: - case EDisplay::TableCaption: - return EDisplay::Block; - case EDisplay::None: + case EDisplay::kContents: + case EDisplay::kInline: + case EDisplay::kInlineBlock: + case EDisplay::kTableRowGroup: + case EDisplay::kTableHeaderGroup: + case EDisplay::kTableFooterGroup: + case EDisplay::kTableRow: + case EDisplay::kTableColumnGroup: + case EDisplay::kTableColumn: + case EDisplay::kTableCell: + case EDisplay::kTableCaption: + return EDisplay::kBlock; + case EDisplay::kNone: ASSERT_NOT_REACHED(); return display; } ASSERT_NOT_REACHED(); - return EDisplay::Block; + return EDisplay::kBlock; } static bool isOutermostSVGElement(const Element* element) { @@ -106,9 +106,9 @@ // considered to be atomic inline-level. static bool doesNotInheritTextDecoration(const ComputedStyle& style, const Element* element) { - return style.display() == EDisplay::InlineTable || - style.display() == EDisplay::InlineBlock || - style.display() == EDisplay::WebkitInlineBox || + return style.display() == EDisplay::kInlineTable || + style.display() == EDisplay::kInlineBlock || + style.display() == EDisplay::kWebkitInlineBox || isAtShadowBoundary(element) || style.isFloating() || style.hasOutOfFlowPosition() || isOutermostSVGElement(element) || isHTMLRTElement(element); @@ -153,7 +153,7 @@ return; // Force inline display (except for floating first-letters). - style.setDisplay(style.isFloating() ? EDisplay::Block : EDisplay::Inline); + style.setDisplay(style.isFloating() ? EDisplay::kBlock : EDisplay::kInline); // CSS2 says first-letter can't be positioned. style.setPosition(EPosition::kStatic); @@ -213,7 +213,7 @@ if (isHTMLImageElement(element)) { if (toHTMLImageElement(element).isCollapsed()) - style.setDisplay(EDisplay::None); + style.setDisplay(EDisplay::kNone); return; } @@ -232,7 +232,7 @@ // This is necessary to fix a crash where a site tries to position these // objects. They also never honor display. style.setPosition(EPosition::kStatic); - style.setDisplay(EDisplay::Block); + style.setDisplay(EDisplay::kBlock); return; } @@ -253,7 +253,7 @@ } if (isHTMLLegendElement(element)) { - style.setDisplay(EDisplay::Block); + style.setDisplay(EDisplay::kBlock); return; } @@ -286,8 +286,8 @@ DCHECK(style.overflowX() != EOverflow::kVisible || style.overflowY() != EOverflow::kVisible); - if (style.display() == EDisplay::Table || - style.display() == EDisplay::InlineTable) { + if (style.display() == EDisplay::kTable || + style.display() == EDisplay::kInlineTable) { // Tables only support overflow:hidden and overflow:visible and ignore // anything else, see http://dev.w3.org/csswg/css2/visufx.html#overflow. As // a table is not a block container box the rules for resolving conflicting @@ -327,36 +327,36 @@ static void adjustStyleForDisplay(ComputedStyle& style, const ComputedStyle& layoutParentStyle, Document* document) { - if (style.display() == EDisplay::Block && !style.isFloating()) + if (style.display() == EDisplay::kBlock && !style.isFloating()) return; - if (style.display() == EDisplay::Contents) + if (style.display() == EDisplay::kContents) return; // FIXME: Don't support this mutation for pseudo styles like first-letter or // first-line, since it's not completely clear how that should work. - if (style.display() == EDisplay::Inline && + if (style.display() == EDisplay::kInline && style.styleType() == PseudoIdNone && style.getWritingMode() != layoutParentStyle.getWritingMode()) - style.setDisplay(EDisplay::InlineBlock); + style.setDisplay(EDisplay::kInlineBlock); // We do not honor position: relative or sticky for table rows, headers, and // footers. This is correct for position: relative in CSS2.1 (and caused a // crash in containingBlock() on some sites) and position: sticky is defined // as following position: relative behavior for table elements. It is // incorrect for CSS3. - if ((style.display() == EDisplay::TableHeaderGroup || - style.display() == EDisplay::TableRowGroup || - style.display() == EDisplay::TableFooterGroup || - style.display() == EDisplay::TableRow) && + if ((style.display() == EDisplay::kTableHeaderGroup || + style.display() == EDisplay::kTableRowGroup || + style.display() == EDisplay::kTableFooterGroup || + style.display() == EDisplay::kTableRow) && style.hasInFlowPosition()) style.setPosition(EPosition::kStatic); // Cannot support position: sticky for table columns and column groups because // current code is only doing background painting through columns / column // groups. - if ((style.display() == EDisplay::TableColumnGroup || - style.display() == EDisplay::TableColumn) && + if ((style.display() == EDisplay::kTableColumnGroup || + style.display() == EDisplay::kTableColumn) && style.position() == EPosition::kSticky) style.setPosition(EPosition::kStatic); @@ -364,21 +364,21 @@ // rows, and table columns. // FIXME: Table cells should be allowed to be perpendicular or flipped with // respect to the table, though. - if (style.display() == EDisplay::TableColumn || - style.display() == EDisplay::TableColumnGroup || - style.display() == EDisplay::TableFooterGroup || - style.display() == EDisplay::TableHeaderGroup || - style.display() == EDisplay::TableRow || - style.display() == EDisplay::TableRowGroup || - style.display() == EDisplay::TableCell) + if (style.display() == EDisplay::kTableColumn || + style.display() == EDisplay::kTableColumnGroup || + style.display() == EDisplay::kTableFooterGroup || + style.display() == EDisplay::kTableHeaderGroup || + style.display() == EDisplay::kTableRow || + style.display() == EDisplay::kTableRowGroup || + style.display() == EDisplay::kTableCell) style.setWritingMode(layoutParentStyle.getWritingMode()); // FIXME: Since we don't support block-flow on flexible boxes yet, disallow // setting of block-flow to anything other than TopToBottomWritingMode. // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support. if (style.getWritingMode() != WritingMode::kHorizontalTb && - (style.display() == EDisplay::WebkitBox || - style.display() == EDisplay::WebkitInlineBox)) + (style.display() == EDisplay::kWebkitBox || + style.display() == EDisplay::kWebkitInlineBox)) style.setWritingMode(WritingMode::kHorizontalTb); if (layoutParentStyle.isDisplayFlexibleOrGridBox()) { @@ -401,7 +401,7 @@ const ComputedStyle& parentStyle, const ComputedStyle& layoutParentStyle, Element* element) { - if (style.display() != EDisplay::None) { + if (style.display() != EDisplay::kNone) { if (element && element->isHTMLElement()) adjustStyleForHTMLElement(style, toHTMLElement(*element)); @@ -414,7 +414,7 @@ // Absolute/fixed positioned elements, floating elements and the document // element need block-like outside display. - if (style.display() != EDisplay::Contents && + if (style.display() != EDisplay::kContents && (style.hasOutOfFlowPosition() || style.isFloating())) style.setDisplay(equivalentBlockDisplay(style.display())); @@ -430,8 +430,8 @@ // Paint containment forces a block formatting context, so we must coerce // from inline. https://drafts.csswg.org/css-containment/#containment-paint - if (style.containsPaint() && style.display() == EDisplay::Inline) - style.setDisplay(EDisplay::Block); + if (style.containsPaint() && style.display() == EDisplay::kInline) + style.setDisplay(EDisplay::kBlock); } else { adjustStyleForFirstLetter(style); } @@ -491,8 +491,8 @@ // SVGElement::layoutObjectIsNeeded. // // [1]: https://www.w3.org/TR/SVG/painting.html#DisplayProperty - if (style.display() == EDisplay::Contents) - style.setDisplay(EDisplay::Inline); + if (style.display() == EDisplay::kContents) + style.setDisplay(EDisplay::kInline); // Only the root <svg> element in an SVG document fragment tree honors css // position. @@ -503,7 +503,7 @@ // SVG text layout code expects us to be a block-level style element. if ((isSVGForeignObjectElement(*element) || isSVGTextElement(*element)) && style.isDisplayInlineType()) - style.setDisplay(EDisplay::Block); + style.setDisplay(EDisplay::kBlock); // Columns don't apply to svg text elements. if (isSVGTextElement(*element))
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index 4353a4a..ac4174a 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -561,7 +561,7 @@ // These are designed to match the user-agent stylesheet values for the // document element so that the common case doesn't need to create a new // ComputedStyle in Document::inheritHtmlAndBodyElementStyles. - documentStyle->setDisplay(EDisplay::Block); + documentStyle->setDisplay(EDisplay::kBlock); documentStyle->setPosition(EPosition::kAbsolute); // Document::inheritHtmlAndBodyElementStyles will set the final overflow @@ -636,7 +636,7 @@ !element->layoutObject()) { if (!s_styleNotYetAvailable) { s_styleNotYetAvailable = ComputedStyle::create().leakRef(); - s_styleNotYetAvailable->setDisplay(EDisplay::None); + s_styleNotYetAvailable->setDisplay(EDisplay::kNone); s_styleNotYetAvailable->font().update( document().styleEngine().fontSelector()); }
diff --git a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp index 69884a3..4381e3f 100644 --- a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
@@ -63,7 +63,7 @@ const ComputedStyle* style = element.computedStyle(); if (!style) return false; - return (style->display() != EDisplay::None && + return (style->display() != EDisplay::kNone && style->visibility() != EVisibility::kHidden && style->opacity() != 0); }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index cde1c10..73df10b 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1574,8 +1574,8 @@ } bool Element::layoutObjectIsNeeded(const ComputedStyle& style) { - return style.display() != EDisplay::None && - style.display() != EDisplay::Contents; + return style.display() != EDisplay::kNone && + style.display() != EDisplay::kContents; } LayoutObject* Element::createLayoutObject(const ComputedStyle& style) { @@ -3196,18 +3196,18 @@ bool Element::hasDisplayContentsStyle() const { if (const ComputedStyle* style = nonLayoutObjectComputedStyle()) - return style->display() == EDisplay::Contents; + return style->display() == EDisplay::kContents; return false; } bool Element::shouldStoreNonLayoutObjectComputedStyle( const ComputedStyle& style) const { #if DCHECK_IS_ON() - if (style.display() == EDisplay::Contents) + if (style.display() == EDisplay::kContents) DCHECK(!layoutObject()); #endif - return style.display() == EDisplay::Contents || + return style.display() == EDisplay::kContents || isHTMLOptGroupElement(*this) || isHTMLOptionElement(*this); }
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.cpp b/third_party/WebKit/Source/core/dom/NodeRareData.cpp index 9343fd3..1bedf95 100644 --- a/third_party/WebKit/Source/core/dom/NodeRareData.cpp +++ b/third_party/WebKit/Source/core/dom/NodeRareData.cpp
@@ -33,7 +33,7 @@ #include "bindings/core/v8/ScriptWrappableVisitor.h" #include "core/dom/Element.h" #include "core/dom/ElementRareData.h" -#include "core/frame/FrameHost.h" +#include "core/page/Page.h" #include "platform/heap/Handle.h" namespace blink { @@ -85,12 +85,12 @@ } void NodeRareData::incrementConnectedSubframeCount() { - SECURITY_CHECK((m_connectedFrameCount + 1) <= FrameHost::maxNumberOfFrames); + SECURITY_CHECK((m_connectedFrameCount + 1) <= Page::maxNumberOfFrames); ++m_connectedFrameCount; } // Ensure the 10 bits reserved for the m_connectedFrameCount cannot overflow -static_assert(FrameHost::maxNumberOfFrames < +static_assert(Page::maxNumberOfFrames < (1 << NodeRareData::ConnectedFrameCountBits), "Frame limit should fit in rare data count");
diff --git a/third_party/WebKit/Source/core/dom/PseudoElement.h b/third_party/WebKit/Source/core/dom/PseudoElement.h index e05dacf..1e9e1aff 100644 --- a/third_party/WebKit/Source/core/dom/PseudoElement.h +++ b/third_party/WebKit/Source/core/dom/PseudoElement.h
@@ -65,7 +65,7 @@ inline bool pseudoElementLayoutObjectIsNeeded(const ComputedStyle* style) { if (!style) return false; - if (style->display() == EDisplay::None) + if (style->display() == EDisplay::kNone) return false; if (style->styleType() == PseudoIdFirstLetter || style->styleType() == PseudoIdBackdrop)
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp index 45618228..938dfec 100644 --- a/third_party/WebKit/Source/core/dom/Range.cpp +++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -1644,8 +1644,9 @@ } void Range::expand(const String& unit, ExceptionState& exceptionState) { + if (!startPosition().isConnected() || !endPosition().isConnected()) + return; m_ownerDocument->updateStyleAndLayoutIgnorePendingStylesheets(); - VisiblePosition start = createVisiblePosition(startPosition()); VisiblePosition end = createVisiblePosition(endPosition()); if (unit == "word") {
diff --git a/third_party/WebKit/Source/core/dom/RangeTest.cpp b/third_party/WebKit/Source/core/dom/RangeTest.cpp index 61ac3b4..d321dcf 100644 --- a/third_party/WebKit/Source/core/dom/RangeTest.cpp +++ b/third_party/WebKit/Source/core/dom/RangeTest.cpp
@@ -12,6 +12,7 @@ #include "core/editing/EditingTestBase.h" #include "core/frame/Settings.h" #include "core/html/HTMLBodyElement.h" +#include "core/html/HTMLDivElement.h" #include "core/html/HTMLDocument.h" #include "core/html/HTMLElement.h" #include "core/html/HTMLHtmlElement.h" @@ -230,4 +231,12 @@ EXPECT_EQ(2u, range->endOffset()); } +// Regression test for crbug.com/698123 +TEST_F(RangeTest, ExpandNotCrash) { + Range* range = Range::create(document()); + Node* div = HTMLDivElement::create(document()); + range->setStart(div, 0, ASSERT_NO_EXCEPTION); + range->expand("", ASSERT_NO_EXCEPTION); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Text.cpp b/third_party/WebKit/Source/core/dom/Text.cpp index 7644a6c..f7510db 100644 --- a/third_party/WebKit/Source/core/dom/Text.cpp +++ b/third_party/WebKit/Source/core/dom/Text.cpp
@@ -265,7 +265,7 @@ if (!length()) return false; - if (style.display() == EDisplay::None) + if (style.display() == EDisplay::kNone) return false; if (!containsOnlyWhitespace())
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp index 76af4bce..53f009d 100644 --- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp +++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -918,7 +918,7 @@ return false; const ComputedStyle* style = node->computedStyle(); - return style && style->display() == EDisplay::Inline; + return style && style->display() == EDisplay::kInline; } // TODO(yosin) Deploy this in all of the places where |enclosingBlockFlow()| and @@ -1066,8 +1066,8 @@ if (!layoutObject) return false; - if (layoutObject->style()->display() == EDisplay::Table || - layoutObject->style()->display() == EDisplay::InlineTable) + if (layoutObject->style()->display() == EDisplay::kTable || + layoutObject->style()->display() == EDisplay::kInlineTable) return true; if (layoutObject->style()->isFloating())
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index 6bb6beb..f1e1a4f 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1416,11 +1416,23 @@ frame().selection().computeVisibleSelectionInDOMTreeDeprecated()) frame().selection().setSelection(newSelection); + if (dispatchBeforeInputInsertText( + eventTargetNodeForDocument(frame().document()), transposed, + InputEvent::InputType::InsertTranspose) != + DispatchEventResult::NotCanceled) + return; + + // 'beforeinput' event handler may destroy document. + if (m_frame->document()->frame() != m_frame) + return; + + // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets + // needs to be audited. see http://crbug.com/590369 for more details. + frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); + // Insert the transposed characters. - // TODO(chongz): Once we add |InsertTranspose| in |InputEvent::InputType|, we - // should use it instead of |InsertFromPaste|. replaceSelectionWithText(transposed, false, false, - InputEvent::InputType::InsertFromPaste); + InputEvent::InputType::InsertTranspose); } void Editor::addToKillRing(const EphemeralRange& range) {
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp index 47629e3..d452857 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -657,6 +657,7 @@ setSelection(SelectionInDOMTree::Builder() .setBaseAndExtent(range) .setAffinity(affinity) + .setIsHandleVisible(isHandleVisible()) .setIsDirectional(directional == SelectionDirectionalMode::Directional) .build(),
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp index d124ac4..9047d80 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -293,4 +293,37 @@ "after it."; } +TEST_F(FrameSelectionTest, SetSelectedRangePreservesHandle) { + Text* text = appendTextNode("Hello, World!"); + document().view()->updateAllLifecyclePhases(); + selection().setSelection( + SelectionInDOMTree::Builder() + .setBaseAndExtent(Position(text, 0), Position(text, 5)) + .setIsHandleVisible(false) + .build()); + + selection().setSelectedRange( + EphemeralRange(Position(text, 0), Position(text, 12)), + VP_DEFAULT_AFFINITY, SelectionDirectionalMode::NonDirectional, 0); + + EXPECT_FALSE(selection().isHandleVisible()) + << "If handles weren't present before" + "setSelectedRange they shouldn't be present" + "after it."; + + selection().setSelection( + SelectionInDOMTree::Builder() + .setBaseAndExtent(Position(text, 0), Position(text, 5)) + .setIsHandleVisible(true) + .build()); + + selection().setSelectedRange( + EphemeralRange(Position(text, 0), Position(text, 12)), + VP_DEFAULT_AFFINITY, SelectionDirectionalMode::NonDirectional, 0); + + EXPECT_TRUE(selection().isHandleVisible()) + << "If handles were present before" + "selectSetSelectedRange they should be present after it."; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/InputEvent.cpp b/third_party/WebKit/Source/core/events/InputEvent.cpp index ff3f83b..0b84074 100644 --- a/third_party/WebKit/Source/core/events/InputEvent.cpp +++ b/third_party/WebKit/Source/core/events/InputEvent.cpp
@@ -26,6 +26,7 @@ {InputEvent::InputType::InsertFromPaste, "insertFromPaste"}, {InputEvent::InputType::InsertFromDrop, "insertFromDrop"}, {InputEvent::InputType::InsertFromYank, "insertFromYank"}, + {InputEvent::InputType::InsertTranspose, "insertTranspose"}, {InputEvent::InputType::InsertReplacementText, "insertReplacementText"}, {InputEvent::InputType::InsertCompositionText, "insertCompositionText"}, {InputEvent::InputType::DeleteWordBackward, "deleteWordBackward"},
diff --git a/third_party/WebKit/Source/core/events/InputEvent.h b/third_party/WebKit/Source/core/events/InputEvent.h index 51cf3892..03d6497 100644 --- a/third_party/WebKit/Source/core/events/InputEvent.h +++ b/third_party/WebKit/Source/core/events/InputEvent.h
@@ -35,6 +35,7 @@ InsertFromPaste, InsertFromDrop, InsertFromYank, + InsertTranspose, InsertReplacementText, InsertCompositionText, // Deletion.
diff --git a/third_party/WebKit/Source/core/frame/FrameConsole.cpp b/third_party/WebKit/Source/core/frame/FrameConsole.cpp index 2c02a9a..113044b 100644 --- a/third_party/WebKit/Source/core/frame/FrameConsole.cpp +++ b/third_party/WebKit/Source/core/frame/FrameConsole.cpp
@@ -69,9 +69,9 @@ } bool FrameConsole::addMessageToStorage(ConsoleMessage* consoleMessage) { - if (!m_frame->document() || !m_frame->host()) + if (!m_frame->document() || !m_frame->page()) return false; - m_frame->host()->consoleMessageStorage().addConsoleMessage( + m_frame->page()->consoleMessageStorage().addConsoleMessage( m_frame->document(), consoleMessage); return true; }
diff --git a/third_party/WebKit/Source/core/frame/FrameHost.cpp b/third_party/WebKit/Source/core/frame/FrameHost.cpp index 226ca913..bd1177f 100644 --- a/third_party/WebKit/Source/core/frame/FrameHost.cpp +++ b/third_party/WebKit/Source/core/frame/FrameHost.cpp
@@ -42,9 +42,7 @@ return new FrameHost(page); } -FrameHost::FrameHost(Page& page) - : m_page(&page), - m_subframeCount(0) {} +FrameHost::FrameHost(Page& page) : m_page(&page) {} // Explicitly in the .cpp to avoid default constructor in .h FrameHost::~FrameHost() {} @@ -73,35 +71,19 @@ return page().overscrollController(); } -ConsoleMessageStorage& FrameHost::consoleMessageStorage() { - return page().consoleMessageStorage(); -} - -const ConsoleMessageStorage& FrameHost::consoleMessageStorage() const { - return page().consoleMessageStorage(); -} - DEFINE_TRACE(FrameHost) { visitor->trace(m_page); } -#if DCHECK_IS_ON() -void checkFrameCountConsistency(int expectedFrameCount, Frame* frame) { - ASSERT(expectedFrameCount >= 0); - - int actualFrameCount = 0; - for (; frame; frame = frame->tree().traverseNext()) - ++actualFrameCount; - - ASSERT(expectedFrameCount == actualFrameCount); +void FrameHost::incrementSubframeCount() { + page().incrementSubframeCount(); } -#endif +void FrameHost::decrementSubframeCount() { + page().decrementSubframeCount(); +} int FrameHost::subframeCount() const { -#if DCHECK_IS_ON() - checkFrameCountConsistency(m_subframeCount + 1, m_page->mainFrame()); -#endif - return m_subframeCount; + return page().subframeCount(); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/FrameHost.h b/third_party/WebKit/Source/core/frame/FrameHost.h index 593a01da..1a8ce9e 100644 --- a/third_party/WebKit/Source/core/frame/FrameHost.h +++ b/third_party/WebKit/Source/core/frame/FrameHost.h
@@ -41,7 +41,6 @@ namespace blink { class BrowserControls; -class ConsoleMessageStorage; class OverscrollController; class Page; @@ -72,29 +71,16 @@ OverscrollController& overscrollController(); const OverscrollController& overscrollController() const; - ConsoleMessageStorage& consoleMessageStorage(); - const ConsoleMessageStorage& consoleMessageStorage() const; - DECLARE_TRACE(); - // Don't allow more than a certain number of frames in a page. - // This seems like a reasonable upper bound, and otherwise mutually - // recursive frameset pages can quickly bring the program to its knees - // with exponential growth in the number of frames. - static const int maxNumberOfFrames = 1000; - void incrementSubframeCount() { ++m_subframeCount; } - void decrementSubframeCount() { - ASSERT(m_subframeCount); - --m_subframeCount; - } + void incrementSubframeCount(); + void decrementSubframeCount(); int subframeCount() const; private: explicit FrameHost(Page&); const Member<Page> m_page; - - int m_subframeCount; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/FrameOwner.h b/third_party/WebKit/Source/core/frame/FrameOwner.h index cbc0741..440b85e 100644 --- a/third_party/WebKit/Source/core/frame/FrameOwner.h +++ b/third_party/WebKit/Source/core/frame/FrameOwner.h
@@ -11,7 +11,6 @@ #include "platform/scroll/ScrollTypes.h" #include "public/platform/WebFeaturePolicy.h" #include "public/platform/WebVector.h" -#include "public/platform/modules/permissions/permission.mojom-blink.h" namespace blink { @@ -50,8 +49,6 @@ virtual bool allowFullscreen() const = 0; virtual bool allowPaymentRequest() const = 0; virtual AtomicString csp() const = 0; - virtual const WebVector<mojom::blink::PermissionName>& delegatedPermissions() - const = 0; virtual const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const = 0; }; @@ -85,12 +82,6 @@ bool allowFullscreen() const override { return false; } bool allowPaymentRequest() const override { return false; } AtomicString csp() const override { return nullAtom; } - const WebVector<mojom::blink::PermissionName>& delegatedPermissions() - const override { - DEFINE_STATIC_LOCAL(WebVector<mojom::blink::PermissionName>, permissions, - ()); - return permissions; - } const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override { DEFINE_STATIC_LOCAL(WebVector<WebFeaturePolicyFeature>, features, ()); return features;
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewport.h b/third_party/WebKit/Source/core/frame/RootFrameViewport.h index 33ccd98..72c87ed6 100644 --- a/third_party/WebKit/Source/core/frame/RootFrameViewport.h +++ b/third_party/WebKit/Source/core/frame/RootFrameViewport.h
@@ -86,9 +86,11 @@ GraphicsLayer* layerForVerticalScrollbar() const override; GraphicsLayer* layerForScrollCorner() const override; int horizontalScrollbarHeight( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; int verticalScrollbarWidth( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; ScrollResult userScroll(ScrollGranularity, const FloatSize&) override; bool scrollAnimatorEnabled() const override; HostWindow* getHostWindow() const override;
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index 4eda6c2..74ba6b1 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1487,6 +1487,7 @@ VRPoseLinearAcceleration = 1864, VRPoseAngularVelocity = 1865, VRPoseAngularAcceleration = 1866, + CSSOverflowPaged = 1867, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn index bcf57722..f605c3d 100644 --- a/third_party/WebKit/Source/core/html/BUILD.gn +++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -85,8 +85,6 @@ "HTMLIFrameElement.cpp", "HTMLIFrameElementAllow.cpp", "HTMLIFrameElementAllow.h", - "HTMLIFrameElementPermissions.cpp", - "HTMLIFrameElementPermissions.h", "HTMLIFrameElementSandbox.cpp", "HTMLIFrameElementSandbox.h", "HTMLImageElement.cpp",
diff --git a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5 b/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5 index 81c2d4d..c09bc0b4 100644 --- a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5 +++ b/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
@@ -293,7 +293,6 @@ "open", "optimum", "pattern", - "permissions", "placeholder", "ping", "poster",
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp index 43b5606b..2ab5f5c 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -123,13 +123,14 @@ EDisplay display = style.display(); bool formIsTablePart = - display == EDisplay::Table || display == EDisplay::InlineTable || - display == EDisplay::TableRowGroup || - display == EDisplay::TableHeaderGroup || - display == EDisplay::TableFooterGroup || display == EDisplay::TableRow || - display == EDisplay::TableColumnGroup || - display == EDisplay::TableColumn || display == EDisplay::TableCell || - display == EDisplay::TableCaption; + display == EDisplay::kTable || display == EDisplay::kInlineTable || + display == EDisplay::kTableRowGroup || + display == EDisplay::kTableHeaderGroup || + display == EDisplay::kTableFooterGroup || + display == EDisplay::kTableRow || + display == EDisplay::kTableColumnGroup || + display == EDisplay::kTableColumn || display == EDisplay::kTableCell || + display == EDisplay::kTableCaption; return formIsTablePart; }
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp index 0efebb76..a2b4602 100644 --- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -33,6 +33,7 @@ #include "core/layout/api/LayoutPartItem.h" #include "core/loader/FrameLoadRequest.h" #include "core/loader/FrameLoader.h" +#include "core/page/Page.h" #include "core/plugins/PluginView.h" #include "platform/weborigin/SecurityOrigin.h" @@ -227,12 +228,6 @@ dispatchScopedEvent(Event::create(EventTypeNames::load)); } -const WebVector<mojom::blink::PermissionName>& -HTMLFrameOwnerElement::delegatedPermissions() const { - DEFINE_STATIC_LOCAL(WebVector<mojom::blink::PermissionName>, permissions, ()); - return permissions; -} - const WebVector<WebFeaturePolicyFeature>& HTMLFrameOwnerElement::allowedFeatures() const { DEFINE_STATIC_LOCAL(WebVector<WebFeaturePolicyFeature>, features, ()); @@ -312,8 +307,7 @@ if (!SubframeLoadingDisabler::canLoadFrame(*this)) return false; - if (document().frame()->host()->subframeCount() >= - FrameHost::maxNumberOfFrames) + if (document().frame()->host()->subframeCount() >= Page::maxNumberOfFrames) return false; FrameLoadRequest frameLoadRequest(&document(), url, "_self",
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h index 7f402265..a80c0d7 100644 --- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h +++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -91,8 +91,6 @@ bool allowFullscreen() const override { return false; } bool allowPaymentRequest() const override { return false; } AtomicString csp() const override { return nullAtom; } - const WebVector<mojom::blink::PermissionName>& delegatedPermissions() - const override; const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp index 90a0daed..a487c30 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -47,7 +47,6 @@ DEFINE_TRACE(HTMLIFrameElement) { visitor->trace(m_sandbox); - visitor->trace(m_permissions); visitor->trace(m_allow); HTMLFrameElementBase::trace(visitor); Supplementable<HTMLIFrameElement>::trace(visitor); @@ -59,12 +58,6 @@ return m_sandbox.get(); } -DOMTokenList* HTMLIFrameElement::permissions() const { - if (!const_cast<HTMLIFrameElement*>(this)->initializePermissionsAttribute()) - return nullptr; - return m_permissions.get(); -} - DOMTokenList* HTMLIFrameElement::allow() const { return m_allow.get(); } @@ -147,9 +140,6 @@ m_allowPaymentRequest = !value.isNull(); if (m_allowPaymentRequest != oldAllowPaymentRequest) frameOwnerPropertiesChanged(); - } else if (name == permissionsAttr) { - if (initializePermissionsAttribute()) - m_permissions->setValue(value); } else if (RuntimeEnabledFeatures::embedderCSPEnforcementEnabled() && name == cspAttr) { // TODO(amalika): add more robust validation of the value @@ -202,21 +192,6 @@ return true; } -void HTMLIFrameElement::permissionsValueWasSet() { - if (!initializePermissionsAttribute()) - return; - - String invalidTokens; - m_delegatedPermissions = - m_permissions->parseDelegatedPermissions(invalidTokens); - if (!invalidTokens.isNull()) - document().addConsoleMessage(ConsoleMessage::create( - OtherMessageSource, ErrorMessageLevel, - "Error while parsing the 'permissions' attribute: " + invalidTokens)); - setSynchronizedLazyAttribute(permissionsAttr, m_permissions->value()); - frameOwnerPropertiesChanged(); -} - void HTMLIFrameElement::sandboxValueWasSet() { String invalidTokens; setSandboxFlags(m_sandbox->value().isNull() @@ -245,13 +220,4 @@ return m_referrerPolicy; } -bool HTMLIFrameElement::initializePermissionsAttribute() { - if (!RuntimeEnabledFeatures::permissionDelegationEnabled()) - return false; - - if (!m_permissions) - m_permissions = HTMLIFrameElementPermissions::create(this); - return true; -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h index b137443..15b659d 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -27,12 +27,10 @@ #include "core/CoreExport.h" #include "core/html/HTMLFrameElementBase.h" #include "core/html/HTMLIFrameElementAllow.h" -#include "core/html/HTMLIFrameElementPermissions.h" #include "core/html/HTMLIFrameElementSandbox.h" #include "platform/Supplementable.h" #include "public/platform/WebFeaturePolicy.h" #include "public/platform/WebVector.h" -#include "public/platform/modules/permissions/permission.mojom-blink.h" namespace blink { @@ -47,11 +45,9 @@ DECLARE_VIRTUAL_TRACE(); ~HTMLIFrameElement() override; DOMTokenList* sandbox() const; - DOMTokenList* permissions() const; DOMTokenList* allow() const; void sandboxValueWasSet(); - void permissionsValueWasSet(); void allowValueWasSet(); private: @@ -81,26 +77,18 @@ bool allowFullscreen() const override { return m_allowFullscreen; } bool allowPaymentRequest() const override { return m_allowPaymentRequest; } AtomicString csp() const override { return m_csp; } - const WebVector<mojom::blink::PermissionName>& delegatedPermissions() - const override { - return m_delegatedPermissions; - } const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override { return m_allowedFeatures; } - bool initializePermissionsAttribute(); - AtomicString m_name; AtomicString m_csp; bool m_didLoadNonEmptyDocument; bool m_allowFullscreen; bool m_allowPaymentRequest; Member<HTMLIFrameElementSandbox> m_sandbox; - Member<HTMLIFrameElementPermissions> m_permissions; Member<HTMLIFrameElementAllow> m_allow; - WebVector<mojom::blink::PermissionName> m_delegatedPermissions; WebVector<WebFeaturePolicyFeature> m_allowedFeatures; ReferrerPolicy m_referrerPolicy;
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl index 862f9aa..c6c13d1d 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
@@ -34,8 +34,6 @@ readonly attribute Window? contentWindow; [CheckSecurity=ReturnValue, RaisesException] Document? getSVGDocument(); [CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy; - // https://noncombatant.github.io/permission-delegation-api/#delegation-via-the-declarative-api - [RuntimeEnabled=PermissionDelegation, PutForwards=value] readonly attribute DOMTokenList permissions; // https://w3c.github.io/webappsec-csp/embedded/#dom-htmliframeelement-csp [RuntimeEnabled=EmbedderCSPEnforcement, CEReactions, Reflect] attribute DOMString csp;
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp deleted file mode 100644 index f5bff6e0..0000000 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSDstyle license that can be -// found in the LICENSE file. - -#include "core/html/HTMLIFrameElementPermissions.h" - -#include "core/html/HTMLIFrameElement.h" -#include "wtf/HashMap.h" -#include "wtf/text/StringBuilder.h" - -namespace blink { - -namespace { - -struct SupportedPermission { - const char* name; - mojom::blink::PermissionName type; -}; - -const SupportedPermission kSupportedPermissions[] = { - {"geolocation", mojom::blink::PermissionName::GEOLOCATION}, - {"notifications", mojom::blink::PermissionName::NOTIFICATIONS}, - {"midi", mojom::blink::PermissionName::MIDI}, -}; - -// Returns true if the name is valid and the type is stored in |result|. -bool getPermissionType(const AtomicString& name, - mojom::blink::PermissionName* result) { - for (const SupportedPermission& permission : kSupportedPermissions) { - if (name == permission.name) { - if (result) - *result = permission.type; - return true; - } - } - return false; -} - -} // namespace - -HTMLIFrameElementPermissions::HTMLIFrameElementPermissions( - HTMLIFrameElement* element) - : DOMTokenList(this), m_element(element) {} - -HTMLIFrameElementPermissions::~HTMLIFrameElementPermissions() {} - -DEFINE_TRACE(HTMLIFrameElementPermissions) { - visitor->trace(m_element); - DOMTokenList::trace(visitor); - DOMTokenListObserver::trace(visitor); -} - -Vector<mojom::blink::PermissionName> -HTMLIFrameElementPermissions::parseDelegatedPermissions( - String& invalidTokensErrorMessage) const { - Vector<blink::mojom::blink::PermissionName> permissions; - unsigned numTokenErrors = 0; - StringBuilder tokenErrors; - const SpaceSplitString& tokens = this->tokens(); - - for (size_t i = 0; i < tokens.size(); ++i) { - blink::mojom::blink::PermissionName type; - if (getPermissionType(tokens[i], &type)) { - permissions.push_back(type); - } else { - tokenErrors.append(tokenErrors.isEmpty() ? "'" : ", '"); - tokenErrors.append(tokens[i]); - tokenErrors.append("'"); - ++numTokenErrors; - } - } - - if (numTokenErrors) { - tokenErrors.append(numTokenErrors > 1 ? " are invalid permissions flags." - : " is an invalid permissions flag."); - invalidTokensErrorMessage = tokenErrors.toString(); - } - - return permissions; -} - -bool HTMLIFrameElementPermissions::validateTokenValue( - const AtomicString& tokenValue, - ExceptionState&) const { - mojom::blink::PermissionName unused; - return getPermissionType(tokenValue, &unused); -} - -void HTMLIFrameElementPermissions::valueWasSet() { - if (m_element) - m_element->permissionsValueWasSet(); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.h b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.h deleted file mode 100644 index 7d0409b..0000000 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSDstyle license that can be -// found in the LICENSE file. - -#ifndef HTMLIFrameElementPermissions_h -#define HTMLIFrameElementPermissions_h - -#include "core/CoreExport.h" -#include "core/dom/DOMTokenList.h" -#include "platform/heap/Handle.h" -#include "public/platform/modules/permissions/permission.mojom-blink.h" -#include "wtf/Vector.h" - -namespace blink { - -class HTMLIFrameElement; - -class CORE_EXPORT HTMLIFrameElementPermissions final - : public DOMTokenList, - public DOMTokenListObserver { - USING_GARBAGE_COLLECTED_MIXIN(HTMLIFrameElementPermissions); - - public: - static HTMLIFrameElementPermissions* create(HTMLIFrameElement* element) { - return new HTMLIFrameElementPermissions(element); - } - - ~HTMLIFrameElementPermissions() override; - - Vector<mojom::blink::PermissionName> parseDelegatedPermissions( - String& invalidTokensErrorMessage) const; - - DECLARE_VIRTUAL_TRACE(); - - private: - explicit HTMLIFrameElementPermissions(HTMLIFrameElement*); - bool validateTokenValue(const AtomicString& tokenValue, - ExceptionState&) const override; - - // DOMTokenListObserver. - void valueWasSet() override; - - Member<HTMLIFrameElement> m_element; -}; - -} // namespace blink - -#endif
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissionsTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissionsTest.cpp deleted file mode 100644 index 920b741..0000000 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissionsTest.cpp +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "core/html/HTMLIFrameElementPermissions.h" - -#include "public/platform/modules/permissions/permission.mojom-blink.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace blink { - -TEST(HTMLIFrameElementPermissionsTest, ParseDelegatedPermissionsValid) { - HTMLIFrameElementPermissions* permissions = - HTMLIFrameElementPermissions::create(nullptr); - Vector<mojom::blink::PermissionName> result; - String errorMessage; - - permissions->setValue("midi"); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(1u, result.size()); - EXPECT_EQ(mojom::blink::PermissionName::MIDI, result[0]); - - permissions->setValue(""); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(0u, result.size()); - - permissions->setValue("geolocation midi"); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(2u, result.size()); - EXPECT_EQ(mojom::blink::PermissionName::GEOLOCATION, result[0]); - EXPECT_EQ(mojom::blink::PermissionName::MIDI, result[1]); -} - -TEST(HTMLIFrameElementPermissionsTest, ParseDelegatedPermissionsInvalid) { - HTMLIFrameElementPermissions* permissions = - HTMLIFrameElementPermissions::create(nullptr); - Vector<mojom::blink::PermissionName> result; - String errorMessage; - - permissions->setValue("midis"); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(0u, result.size()); - EXPECT_EQ("'midis' is an invalid permissions flag.", errorMessage); - - permissions->setValue("geolocations midis"); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(0u, result.size()); - EXPECT_EQ("'geolocations', 'midis' are invalid permissions flags.", - errorMessage); - - permissions->setValue("geolocation midis"); - result = permissions->parseDelegatedPermissions(errorMessage); - EXPECT_EQ(1u, result.size()); - EXPECT_EQ(mojom::blink::PermissionName::GEOLOCATION, result[0]); - EXPECT_EQ("'midis' is an invalid permissions flag.", errorMessage); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp index 765ef853..a84b500 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
@@ -9,26 +9,6 @@ namespace blink { -// Test setting permission via the Element attribute (HTML codepath). -TEST(HTMLIFrameElementTest, SetPermissionsAttribute) { - Document* document = Document::create(); - HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document); - - iframe->setAttribute(HTMLNames::permissionsAttr, "geolocation"); - EXPECT_EQ("geolocation", iframe->permissions()->value()); - iframe->setAttribute(HTMLNames::permissionsAttr, "geolocation notifications"); - EXPECT_EQ("geolocation notifications", iframe->permissions()->value()); -} - -// Test setting permission via the DOMTokenList (JS codepath). -TEST(HTMLIFrameElementTest, SetPermissionsAttributeJS) { - Document* document = Document::create(); - HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document); - - iframe->permissions()->setValue("midi"); - EXPECT_EQ("midi", iframe->getAttribute(HTMLNames::permissionsAttr)); -} - // Test setting feature policy via the Element attribute (HTML codepath). TEST(HTMLIFrameElementTest, SetAllowAttribute) { Document* document = Document::create();
diff --git a/third_party/WebKit/Source/core/html/HTMLImageFallbackHelper.cpp b/third_party/WebKit/Source/core/html/HTMLImageFallbackHelper.cpp index cbf51fa..bc2f771 100644 --- a/third_party/WebKit/Source/core/html/HTMLImageFallbackHelper.cpp +++ b/third_party/WebKit/Source/core/html/HTMLImageFallbackHelper.cpp
@@ -124,7 +124,7 @@ !newStyle->width().isSpecifiedOrIntrinsic() && !newStyle->height().isSpecifiedOrIntrinsic() && toHTMLElement(element).altText().isEmpty()) - newStyle->setDisplay(EDisplay::None); + newStyle->setDisplay(EDisplay::kNone); // This preserves legacy behaviour originally defined when alt-text was // managed by LayoutImage.
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp index a169c3f..10cb65b 100644 --- a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
@@ -417,7 +417,7 @@ if (!style) return false; - if (style->display() != EDisplay::None) { + if (style->display() != EDisplay::kNone) { // We need to check the parent's display property. Parent's // display:none doesn't override children's display properties in // ComputedStyle. @@ -427,10 +427,10 @@ const ComputedStyle* parentStyle = parent->computedStyle() ? parent->computedStyle() : parent->ensureComputedStyle(); - return !parentStyle || parentStyle->display() == EDisplay::None; + return !parentStyle || parentStyle->display() == EDisplay::kNone; } } - return style->display() == EDisplay::None; + return style->display() == EDisplay::kNone; } String HTMLOptionElement::innerText() {
diff --git a/third_party/WebKit/Source/core/html/HTMLRTElement.cpp b/third_party/WebKit/Source/core/html/HTMLRTElement.cpp index 65bb354..fba8132 100644 --- a/third_party/WebKit/Source/core/html/HTMLRTElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLRTElement.cpp
@@ -17,7 +17,7 @@ DEFINE_NODE_FACTORY(HTMLRTElement) LayoutObject* HTMLRTElement::createLayoutObject(const ComputedStyle& style) { - if (style.display() == EDisplay::Block) + if (style.display() == EDisplay::kBlock) return new LayoutRubyText(this); return LayoutObject::createObject(this, style); }
diff --git a/third_party/WebKit/Source/core/html/HTMLRubyElement.cpp b/third_party/WebKit/Source/core/html/HTMLRubyElement.cpp index 966eb222..cb7b429e 100644 --- a/third_party/WebKit/Source/core/html/HTMLRubyElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLRubyElement.cpp
@@ -17,9 +17,9 @@ DEFINE_NODE_FACTORY(HTMLRubyElement) LayoutObject* HTMLRubyElement::createLayoutObject(const ComputedStyle& style) { - if (style.display() == EDisplay::Inline) + if (style.display() == EDisplay::kInline) return new LayoutRubyAsInline(this); - if (style.display() == EDisplay::Block) + if (style.display() == EDisplay::kBlock) return new LayoutRubyAsBlock(this); return LayoutObject::createObject(this, style); }
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp index 8ee20dd..a37093e 100644 --- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -1834,7 +1834,7 @@ if (isHTMLOptionElement(element)) return toHTMLOptionElement(element).isDisplayNone(); if (const ComputedStyle* style = itemComputedStyle(element)) - return style->display() == EDisplay::None; + return style->display() == EDisplay::kNone; return false; }
diff --git a/third_party/WebKit/Source/core/html/HTMLSummaryElement.cpp b/third_party/WebKit/Source/core/html/HTMLSummaryElement.cpp index f789441..a5e0740 100644 --- a/third_party/WebKit/Source/core/html/HTMLSummaryElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSummaryElement.cpp
@@ -47,8 +47,8 @@ LayoutObject* HTMLSummaryElement::createLayoutObject( const ComputedStyle& style) { EDisplay display = style.display(); - if (display == EDisplay::Flex || display == EDisplay::InlineFlex || - display == EDisplay::Grid || display == EDisplay::InlineGrid) + if (display == EDisplay::kFlex || display == EDisplay::kInlineFlex || + display == EDisplay::kGrid || display == EDisplay::kInlineGrid) return LayoutObject::createObject(this, style); return new LayoutBlockFlow(this); }
diff --git a/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp b/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp index 2094e3a6..11bed40 100644 --- a/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp +++ b/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp
@@ -333,11 +333,11 @@ PassRefPtr<ComputedStyle> originalStyle) { EDisplay originalDisplay = originalStyle->display(); EDisplay newDisplay = originalDisplay; - if (originalDisplay == EDisplay::Inline || - originalDisplay == EDisplay::InlineBlock) - newDisplay = EDisplay::InlineFlex; - else if (originalDisplay == EDisplay::Block) - newDisplay = EDisplay::Flex; + if (originalDisplay == EDisplay::kInline || + originalDisplay == EDisplay::kInlineBlock) + newDisplay = EDisplay::kInlineFlex; + else if (originalDisplay == EDisplay::kBlock) + newDisplay = EDisplay::kFlex; TextDirection contentDirection = computedTextDirection(); if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
diff --git a/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp b/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp index 7ba751e3..5c3e19fa 100644 --- a/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp +++ b/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp
@@ -81,7 +81,7 @@ style->setFlexGrow(1); style->setMinWidth(Length(0, Fixed)); - style->setDisplay(EDisplay::Block); + style->setDisplay(EDisplay::kBlock); style->setDirection(TextDirection::kLtr); // We don't want the shadow dom to be editable, so we set this block to
diff --git a/third_party/WebKit/Source/core/inspector/BUILD.gn b/third_party/WebKit/Source/core/inspector/BUILD.gn index 42eec860..1a179aafe 100644 --- a/third_party/WebKit/Source/core/inspector/BUILD.gn +++ b/third_party/WebKit/Source/core/inspector/BUILD.gn
@@ -92,24 +92,29 @@ ] } -action("instrumentation_sources") { +# instrumentation probes ------------------------------------------------------- + +action("instrumentation_probes") { visibility = [ ":*" ] - script = "CodeGeneratorInstrumentation.py" + script = "InstrumentingProbesCodeGenerator.py" inputs = [ # Input file for the script. - "InspectorInstrumentation.idl", + "InstrumentingProbes.idl", + "InstrumentingProbesImpl_cpp.template", + "InstrumentingProbesImpl_h.template", + "InstrumentingAgents_h.template", ] outputs = [ "$blink_core_output_dir/InspectorInstrumentationInl.h", "$blink_core_output_dir/InspectorOverridesInl.h", + "$blink_core_output_dir/InstrumentingProbesImpl.cpp", "$blink_core_output_dir/InstrumentingAgents.h", - "$blink_core_output_dir/InspectorInstrumentationImpl.cpp", ] args = [ - rebase_path("InspectorInstrumentation.idl", root_build_dir), + rebase_path("InstrumentingProbes.idl", root_build_dir), "--output_dir", rebase_path(blink_core_output_dir, root_build_dir), ] @@ -194,7 +199,7 @@ # Compiles the sources generated above. source_set("generated") { sources = get_target_outputs(":protocol_sources") + - get_target_outputs(":instrumentation_sources") + get_target_outputs(":instrumentation_probes") configs -= core_config_remove configs += core_config_add + [ @@ -207,7 +212,7 @@ } deps = [ - ":instrumentation_sources", + ":instrumentation_probes", ":protocol_sources", "//skia", "//third_party/WebKit/Source/bindings/core/v8:bindings_core_v8_generated",
diff --git a/third_party/WebKit/Source/core/inspector/CodeGeneratorInstrumentation.py b/third_party/WebKit/Source/core/inspector/CodeGeneratorInstrumentation.py deleted file mode 100755 index cc3c1b1..0000000 --- a/third_party/WebKit/Source/core/inspector/CodeGeneratorInstrumentation.py +++ /dev/null
@@ -1,559 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import optparse -import re -import string -import sys - -template_h = string.Template("""// Code generated from InspectorInstrumentation.idl - -#ifndef ${file_name}_h -#define ${file_name}_h - -${includes} - -namespace blink { - -${forward_declarations} - -namespace probe { - -$methods -} // namespace probe -} // namespace blink - -#endif // !defined(${file_name}_h) -""") - -template_cpp = string.Template("""// Code generated from InspectorInstrumentation.idl - -${includes} - -namespace blink { -${extra_definitions} - -namespace probe { - -$methods - -} // namespace probe -} // namespace blink -""") - -template_scoped_decl = string.Template(""" -class CORE_EXPORT ${name} : public ProbeBase { - STACK_ALLOCATED() -public: - explicit $name($param_list); - ~${name}(); -${member_list} -};""") - -template_impl = string.Template(""" -${return_type} ${name}(${params}) -{ - InstrumentingAgents* agents = instrumentingAgentsFor(${first_param_name}); - if (!agents) - ${default_return}${impl_lines}${maybe_default_return} -}""") - -template_agent_call = string.Template(""" - if (agents->has${agent_class}s()) { - for (${agent_class}* agent : agents->${agent_getter}s()) - ${maybe_return}agent->${name}(${params_agent}); - }""") - -template_scoped_impl = string.Template(""" -${name}::${name}(${params})${init_list} -{ - InstrumentingAgents* agents = instrumentingAgentsFor(${first_param_name}); - if (!agents) - return;${will_body_lines} -} -${name}::~${name}() -{ - InstrumentingAgents* agents = instrumentingAgentsFor(${first_param_name}); - if (!agents) - return;${did_body_lines} -}""") - -template_instrumenting_agents_h = string.Template("""// Code generated from InspectorInstrumentation.idl - -#ifndef InstrumentingAgents_h -#define InstrumentingAgents_h - -#include "core/CoreExport.h" -#include "platform/heap/Handle.h" -#include "wtf/Allocator.h" -#include "wtf/Noncopyable.h" -#include "wtf/PassRefPtr.h" - -namespace blink { - -${forward_list} - -class CORE_EXPORT InstrumentingAgents : public GarbageCollected<InstrumentingAgents> { - WTF_MAKE_NONCOPYABLE(InstrumentingAgents); -public: - InstrumentingAgents(); - DECLARE_TRACE(); -${accessor_list} - -private: -${member_list} -}; - -} - -#endif // !defined(InstrumentingAgents_h) -""") - -template_instrumenting_agent_accessor = string.Template(""" - bool has${class_name}s() const { return ${has_member_name}; } - const HeapHashSet<Member<${class_name}>>& ${getter_name}s() const { return ${member_name}; } - void add${class_name}(${class_name}* agent); - void remove${class_name}(${class_name}* agent);""") - -template_instrumenting_agent_impl = string.Template(""" -void InstrumentingAgents::add${class_name}(${class_name}* agent) -{ - ${member_name}.insert(agent); - ${has_member_name} = true; -} - -void InstrumentingAgents::remove${class_name}(${class_name}* agent) -{ - ${member_name}.erase(agent); - ${has_member_name} = !${member_name}.isEmpty(); -} -""") - -template_instrumenting_agents_cpp = string.Template(""" -InstrumentingAgents::InstrumentingAgents() - : $init_list -{ -} -${impl_list} -DEFINE_TRACE(InstrumentingAgents) -{ - $trace_list -}""") - - - -def match_and_consume(pattern, source): - match = re.match(pattern, source) - if match: - return match, source[len(match.group(0)):].strip() - return None, source - - -def load_model_from_idl(source): - source = re.sub("//.*", "", source) # Remove line comments - source = re.sub("/\*(.|\n)*?\*/", "", source, re.MULTILINE) # Remove block comments - source = re.sub("\]\s*?\n\s*", "] ", source) # Merge the method annotation with the next line - source = source.strip() - - model = [] - - while len(source): - match, source = match_and_consume("interface\s(\w*)\s?\{([^\{]*)\}", source) - if not match: - sys.stderr.write("Cannot parse %s\n" % source[:100]) - sys.exit(1) - model.append(File(match.group(1), match.group(2))) - - return model - - -class File: - def __init__(self, name, source): - self.name = name - self.header_name = self.name + "Inl" - self.includes = [include_inspector_header("InspectorInstrumentation")] - self.forward_declarations = [] - self.declarations = [] - for line in map(str.strip, source.split("\n")): - line = re.sub("\s{2,}", " ", line).strip() # Collapse whitespace - if len(line) == 0: - continue - if line[0] == "#": - self.includes.append(line) - elif line.startswith("class "): - self.forward_declarations.append(line) - else: - self.declarations.append(Method(line)) - self.includes.sort() - self.forward_declarations.sort() - - def generate(self, cpp_lines, used_agents): - header_lines = [] - for declaration in self.declarations: - for agent in set(declaration.agents): - used_agents.add(agent) - declaration.generate_header(header_lines) - declaration.generate_cpp(cpp_lines) - - return template_h.substitute(None, - file_name=self.header_name, - includes="\n".join(self.includes), - forward_declarations="\n".join(self.forward_declarations), - methods="\n".join(header_lines)) - - -class Method: - def __init__(self, source): - match = re.match("(\[[\w|,|=|\s]*\])?\s?(\w*\*?) (\w*)\((.*)\)\s?;", source) - if not match: - sys.stderr.write("Cannot parse %s\n" % source) - sys.exit(1) - - self.options = [] - if match.group(1): - options_str = re.sub("\s", "", match.group(1)[1:-1]) - if len(options_str) != 0: - self.options = options_str.split(",") - - self.return_type = match.group(2) - - self.name = match.group(3) - - # Splitting parameters by a comma, assuming that attribute lists contain no more than one attribute. - self.params = map(Parameter, map(str.strip, match.group(4).split(","))) - - self.returns_value = self.return_type == "bool" - if self.return_type == "bool": - self.default_return_value = "false" - elif self.returns_value: - sys.stderr.write("Can only return bool: %s\n" % self.name) - sys.exit(1) - - self.params_agent = self.params - if "Keep" not in self.params_agent[0].options: - self.params_agent = self.params_agent[1:] - - self.agents = filter(lambda option: not "=" in option, self.options) - - if self.returns_value and len(self.agents) > 1: - sys.stderr.write("Can only return value from a single agent: %s\n" % self.name) - sys.exit(1) - - def is_scoped(self): - return self.return_type == "" - - def generate_header(self, header_lines): - param_list = ", ".join(map(Parameter.to_str_class_and_value, self.params)) - if self.is_scoped(): - member_list = "\n".join(map(generate_member_decl, self.params)) - header_lines.append(template_scoped_decl.substitute( - None, - name=self.name, - param_list=param_list, - member_list=member_list)) - else: - header_lines.append("CORE_EXPORT %s %s(%s);" % ( - self.return_type, self.name, param_list)) - - def generate_cpp(self, cpp_lines): - if self.is_scoped(): - self.generate_scoped_cpp(cpp_lines) - else: - self.generate_unscoped_cpp(cpp_lines) - - def generate_scoped_cpp(self, cpp_lines): - will_body_lines = map(self.generate_ref_ptr, self.params) - will_body_lines += [self.generate_scoped_agent_call("will", agent) for agent in self.agents] - did_body_lines = map(self.generate_ref_ptr, self.params) - did_body_lines += [self.generate_scoped_agent_call("did", agent) for agent in self.agents] - member_init = ",\n".join(map(generate_member_init, self.params)) - - cpp_lines.append(template_scoped_impl.substitute( - None, - name=self.name, - params=", ".join(map(Parameter.to_str_class_and_name, self.params)), - init_list=":\n" + member_init if len(member_init) > 0 else "", - will_body_lines="".join(will_body_lines), - did_body_lines="".join(did_body_lines), - first_param_name=self.params[0].name)) - - def generate_scoped_agent_call(self, name, agent): - agent_class, agent_getter = agent_getter_signature(agent) - return template_agent_call.substitute( - None, - name=name, - agent_class=agent_class, - agent_getter=agent_getter, - maybe_return="", - params_agent="*this") - - def generate_unscoped_cpp(self, cpp_lines): - default_return = "return;" - maybe_default_return = "" - if self.returns_value: - default_return = "return %s;" % self.default_return_value - maybe_default_return = "\n " + default_return - - body_lines = map(self.generate_ref_ptr, self.params) - body_lines += map(self.generate_agent_call, self.agents) - - cpp_lines.append(template_impl.substitute( - None, - name=self.name, - return_type=self.return_type, - params=", ".join(map(Parameter.to_str_class_and_name, self.params)), - default_return=default_return, - maybe_default_return=maybe_default_return, - impl_lines="".join(body_lines), - first_param_name=self.params[0].name)) - - def generate_agent_call(self, agent): - agent_class, agent_getter = agent_getter_signature(agent) - - maybe_return = "" - if self.returns_value: - maybe_return = "return " - - return template_agent_call.substitute( - None, - name=self.name, - agent_class=agent_class, - agent_getter=agent_getter, - maybe_return=maybe_return, - params_agent=", ".join(map(Parameter.to_str_value, self.params_agent))) - - def generate_ref_ptr(self, param): - if param.is_prp: - return "\n RefPtr<%s> %s = %s;" % (param.inner_type, param.value, param.name) - else: - return "" - -class Parameter: - def __init__(self, source): - self.options = [] - match, source = match_and_consume("\[(\w*)\]", source) - if match: - self.options.append(match.group(1)) - - parts = map(str.strip, source.split("=")) - if len(parts) == 1: - self.default_value = None - else: - self.default_value = parts[1] - - param_decl = parts[0] - - if re.match("(const|unsigned long) ", param_decl): - min_type_tokens = 2 - else: - min_type_tokens = 1 - - if len(param_decl.split(" ")) > min_type_tokens: - parts = param_decl.split(" ") - self.type = " ".join(parts[:-1]) - self.name = parts[-1] - else: - self.type = param_decl - self.name = generate_param_name(self.type) - - if re.match("PassRefPtr<", param_decl): - self.is_prp = True - self.value = self.name - self.name = "prp" + self.name[0].upper() + self.name[1:] - self.inner_type = re.match("PassRefPtr<(.+)>", param_decl).group(1) - else: - self.is_prp = False - self.value = self.name - - self.is_ptr = self.type[-1] == "*" - - def to_str_full(self): - if self.default_value is None: - return self.to_str_class_and_name() - return "%s %s = %s" % (self.type, self.name, self.default_value) - - def to_str_class_and_name(self): - return "%s %s" % (self.type, self.name) - - def to_str_class_and_value(self): - if self.default_value: - return "%s = %s" % (self.to_str_class(), self.default_value) - return self.to_str_class() - - def to_str_class(self): - return self.type - - def to_str_name(self): - return self.name - - def to_str_value(self): - return self.value - - -def generate_param_name(param_type): - base_name = re.match("(const |PassRefPtr<)?(\w*)", param_type).group(2) - return "param" + base_name - - -def generate_member_decl(param): - if param.is_ptr and "char" not in param.type: - return " Member<%s> %s;" % (param.type[:-1], param.name) - else: - return " %s %s;" % (param.type, param.name) - - -def generate_member_init(param): - return " %s(%s)" % (param.name, param.name) - - -def agent_class_name(agent): - if agent == "Performance": - return "PerformanceMonitor" - if agent == "TraceEvents": - return "InspectorTraceEvents" - return "Inspector%sAgent" % agent - - -def agent_getter_signature(agent): - agent_class = agent_class_name(agent) - return agent_class, agent_class[0].lower() + agent_class[1:] - - -def include_header(name): - return "#include \"%s.h\"" % name - - -def include_inspector_header(name): - if name == "PerformanceMonitor": - return include_header("core/frame/" + name) - return include_header("core/inspector/" + name) - - -def generate_instrumenting_agents(used_agents): - agents = list(used_agents) - agents.sort() - - forward_list = [] - accessor_list = [] - member_list = [] - init_list = [] - trace_list = [] - impl_list = [] - - for agent in agents: - class_name, getter_name = agent_getter_signature(agent) - member_name = "m_" + getter_name + "s" - has_member_name = "m_has" + class_name + "s" - - forward_list.append("class %s;" % class_name) - accessor_list.append(template_instrumenting_agent_accessor.substitute( - None, - class_name=class_name, - getter_name=getter_name, - member_name=member_name, - has_member_name=has_member_name)) - member_list.append(" HeapHashSet<Member<%s>> %s;" % (class_name, member_name)) - member_list.append(" bool %s;" % has_member_name) - init_list.append("%s(false)" % has_member_name) - trace_list.append("visitor->trace(%s);" % member_name) - impl_list.append(template_instrumenting_agent_impl.substitute( - None, - class_name=class_name, - member_name=member_name, - has_member_name=has_member_name)) - - header_lines = template_instrumenting_agents_h.substitute( - None, - forward_list="\n".join(forward_list), - accessor_list="\n".join(accessor_list), - member_list="\n".join(member_list)) - - cpp_lines = template_instrumenting_agents_cpp.substitute( - None, - init_list="\n , ".join(init_list), - impl_list="".join(impl_list), - trace_list="\n ".join(trace_list)) - - return header_lines, cpp_lines - - -def generate(input_path, output_dir): - fin = open(input_path, "r") - files = load_model_from_idl(fin.read()) - fin.close() - - cpp_includes = [] - cpp_lines = [] - used_agents = set() - for f in files: - cpp_includes.append(include_header(f.header_name)) - - fout = open(output_dir + "/" + f.header_name + ".h", "w") - fout.write(f.generate(cpp_lines, used_agents)) - fout.close() - - for agent in used_agents: - cpp_includes.append(include_inspector_header(agent_class_name(agent))) - cpp_includes.append(include_header("InstrumentingAgents")) - cpp_includes.append(include_header("core/CoreExport")) - cpp_includes.sort() - - instrumenting_agents_header, instrumenting_agents_cpp = generate_instrumenting_agents(used_agents) - - fout = open(output_dir + "/" + "InstrumentingAgents.h", "w") - fout.write(instrumenting_agents_header) - fout.close() - - fout = open(output_dir + "/InspectorInstrumentationImpl.cpp", "w") - fout.write(template_cpp.substitute(None, - includes="\n".join(cpp_includes), - extra_definitions=instrumenting_agents_cpp, - methods="\n".join(cpp_lines))) - fout.close() - - -cmdline_parser = optparse.OptionParser() -cmdline_parser.add_option("--output_dir") - -try: - arg_options, arg_values = cmdline_parser.parse_args() - if (len(arg_values) != 1): - raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values)) - input_path = arg_values[0] - output_dirpath = arg_options.output_dir - if not output_dirpath: - raise Exception("Output directory must be specified") -except Exception: - # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html - exc = sys.exc_info()[1] - sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) - sys.stderr.write("Usage: <script> --output_dir <output_dir> InspectorInstrumentation.idl\n") - exit(1) - -generate(input_path, output_dirpath)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp index a16579e..607b3a7 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp
@@ -79,10 +79,12 @@ m_task(task), m_recurring(step) { if (m_recurring) { - TRACE_EVENT_FLOW_STEP0("devtools.timeline.async", "AsyncTask", task, + TRACE_EVENT_FLOW_STEP0("devtools.timeline.async", "AsyncTask", + TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)), step ? step : ""); } else { - TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask", task); + TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask", + TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task))); } if (m_debugger) m_debugger->asyncTaskStarted(m_task); @@ -99,8 +101,9 @@ void asyncTaskScheduled(ExecutionContext* context, const String& name, void* task) { - TRACE_EVENT_FLOW_BEGIN1("devtools.timeline.async", "AsyncTask", task, "data", - InspectorAsyncTask::data(name)); + TRACE_EVENT_FLOW_BEGIN1("devtools.timeline.async", "AsyncTask", + TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task)), + "data", InspectorAsyncTask::data(name)); if (ThreadDebugger* debugger = ThreadDebugger::from(toIsolate(context))) debugger->asyncTaskScheduled(name, task, true); } @@ -115,7 +118,8 @@ void asyncTaskCanceled(ExecutionContext* context, void* task) { if (ThreadDebugger* debugger = ThreadDebugger::from(toIsolate(context))) debugger->asyncTaskCanceled(task); - TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask", task); + TRACE_EVENT_FLOW_END0("devtools.timeline.async", "AsyncTask", + TRACE_ID_LOCAL(reinterpret_cast<uintptr_t>(task))); } void asyncTaskCanceledBreakable(ExecutionContext* context,
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp index 01d1470..978f3ba 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -45,6 +45,14 @@ namespace blink { +namespace { + +void* asyncId(unsigned long identifier) { + return reinterpret_cast<void*>((identifier << 1) | 1); +} + +} // namespace + String toHexString(const void* p) { return String::format("0x%" PRIx64, static_cast<uint64_t>(reinterpret_cast<uintptr_t>(p))); @@ -92,6 +100,8 @@ TRACE_EVENT_INSTANT1( "devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorSendRequestEvent::data(identifier, frame, request)); + probe::asyncTaskScheduled(frame->document(), "SendRequest", + asyncId(identifier)); } void InspectorTraceEvents::didReceiveResourceResponse( @@ -103,6 +113,8 @@ TRACE_EVENT_INSTANT1( "devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, frame, response)); + probe::AsyncTask asyncTask(frame->document(), asyncId(identifier), + "response"); } void InspectorTraceEvents::didReceiveData(LocalFrame* frame, @@ -113,6 +125,7 @@ "devtools.timeline", "ResourceReceivedData", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveDataEvent::data(identifier, frame, encodedDataLength)); + probe::AsyncTask asyncTask(frame->document(), asyncId(identifier), "data"); } void InspectorTraceEvents::didFinishLoading(LocalFrame* frame, @@ -124,6 +137,7 @@ "devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(identifier, finishTime, false, encodedDataLength, decodedBodyLength)); + probe::AsyncTask asyncTask(frame->document(), asyncId(identifier)); } void InspectorTraceEvents::didFailLoading(unsigned long identifier,
diff --git a/third_party/WebKit/Source/core/inspector/InstrumentingAgents_h.template b/third_party/WebKit/Source/core/inspector/InstrumentingAgents_h.template new file mode 100644 index 0000000..1a90db1 --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/InstrumentingAgents_h.template
@@ -0,0 +1,46 @@ +// This file is generated from {{input_file}} + +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef InstrumentingAgents_h +#define InstrumentingAgents_h + +#include "core/CoreExport.h" +#include "platform/heap/HeapAllocator.h" + +namespace blink { + +{% for agent in agents %} +class {{ agent | agent_name_to_class }}; +{% endfor %} + +class CORE_EXPORT InstrumentingAgents : public GarbageCollected<InstrumentingAgents> { + WTF_MAKE_NONCOPYABLE(InstrumentingAgents); + + public: + InstrumentingAgents(); + DECLARE_TRACE(); + +{% for agent in agents %} +{% set class_name = agent | agent_name_to_class %} +{% set getter_name = class_name | to_lower_case %} + bool has{{class_name}}s() const { return m_has{{class_name}}s; } + const HeapHashSet<Member<{{class_name}}>>& {{getter_name}}s() const { return m_{{getter_name}}s; } + void add{{class_name}}({{class_name}}* agent); + void remove{{class_name}}({{class_name}}* agent); + +{% endfor %} + private: +{% for agent in agents %} +{% set class_name = agent | agent_name_to_class %} +{% set getter_name = class_name | to_lower_case %} + HeapHashSet<Member<{{class_name}}>> m_{{getter_name}}s; + bool m_has{{class_name}}s = false; +{% endfor %} +}; + +} // namespace blink + +#endif // !defined(InstrumentingAgents_h)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl b/third_party/WebKit/Source/core/inspector/InstrumentingProbes.idl similarity index 100% rename from third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl rename to third_party/WebKit/Source/core/inspector/InstrumentingProbes.idl
diff --git a/third_party/WebKit/Source/core/inspector/InstrumentingProbesCodeGenerator.py b/third_party/WebKit/Source/core/inspector/InstrumentingProbesCodeGenerator.py new file mode 100644 index 0000000..d334bf6 --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/InstrumentingProbesCodeGenerator.py
@@ -0,0 +1,233 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import optparse +import os.path +import re +import sys + +# Path handling for libraries and templates +# Paths have to be normalized because Jinja uses the exact template path to +# determine the hash used in the cache filename, and we need a pre-caching step +# to be concurrency-safe. Use absolute path because __file__ is absolute if +# module is imported, and relative if executed directly. +# If paths differ between pre-caching and individual file compilation, the cache +# is regenerated, which causes a race condition and breaks concurrent build, +# since some compile processes will try to read the partially written cache. +module_path, module_filename = os.path.split(os.path.realpath(__file__)) +templates_dir = module_path +third_party_dir = os.path.normpath(os.path.join( + module_path, os.pardir, os.pardir, os.pardir, os.pardir)) +# jinja2 is in chromium's third_party directory. +# Insert at 1 so at front to override system libraries, and +# after path[0] == invoking script dir +sys.path.insert(1, third_party_dir) +import jinja2 + + +def to_lower_case(name): + return name[:1].lower() + name[1:] + + +def agent_name_to_class(agent_name): + if agent_name == "Performance": + return "PerformanceMonitor" + elif agent_name == "TraceEvents": + return "InspectorTraceEvents" + else: + return "Inspector%sAgent" % agent_name + + +def initialize_jinja_env(cache_dir): + jinja_env = jinja2.Environment( + loader=jinja2.FileSystemLoader(templates_dir), + # Bytecode cache is not concurrency-safe unless pre-cached: + # if pre-cached this is read-only, but writing creates a race condition. + bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), + keep_trailing_newline=True, # newline-terminate generated files + lstrip_blocks=True, # so can indent control flow tags + trim_blocks=True) + jinja_env.filters.update({ + "to_lower_case": to_lower_case, + "agent_name_to_class": agent_name_to_class}) + jinja_env.add_extension('jinja2.ext.loopcontrols') + return jinja_env + + +def match_and_consume(pattern, source): + match = re.match(pattern, source) + if match: + return match, source[len(match.group(0)):].strip() + return None, source + + +def load_model_from_idl(source): + source = re.sub(r"//.*", "", source) # Remove line comments + source = re.sub(r"/\*(.|\n)*?\*/", "", source, re.MULTILINE) # Remove block comments + source = re.sub(r"\]\s*?\n\s*", "] ", source) # Merge the method annotation with the next line + source = source.strip() + model = [] + while len(source): + match, source = match_and_consume(r"interface\s(\w*)\s?\{([^\{]*)\}", source) + if not match: + sys.stderr.write("Cannot parse %s\n" % source[:100]) + sys.exit(1) + model.append(File(match.group(1), match.group(2))) + return model + + +class File(object): + def __init__(self, name, source): + self.name = name + self.header_name = self.name + "Inl" + self.includes = [include_inspector_header("InspectorInstrumentation")] + self.forward_declarations = [] + self.declarations = [] + for line in map(str.strip, source.split("\n")): + line = re.sub(r"\s{2,}", " ", line).strip() # Collapse whitespace + if len(line) == 0: + continue + if line[0] == "#": + self.includes.append(line) + elif line.startswith("class "): + self.forward_declarations.append(line) + else: + self.declarations.append(Method(line)) + self.includes.sort() + self.forward_declarations.sort() + + +def include_header(name): + return "#include \"%s.h\"" % name + + +def include_inspector_header(name): + if name == "PerformanceMonitor": + return include_header("core/frame/" + name) + return include_header("core/inspector/" + name) + + +class Method(object): + def __init__(self, source): + match = re.match(r"(\[[\w|,|=|\s]*\])?\s?(\w*\*?) (\w*)\((.*)\)\s?;", source) + if not match: + sys.stderr.write("Cannot parse %s\n" % source) + sys.exit(1) + + self.options = [] + if match.group(1): + options_str = re.sub(r"\s", "", match.group(1)[1:-1]) + if len(options_str) != 0: + self.options = options_str.split(",") + + self.return_type = match.group(2) + self.name = match.group(3) + self.is_scoped = self.return_type == "" + + # Splitting parameters by a comma, assuming that attribute lists contain no more than one attribute. + self.params = map(Parameter, map(str.strip, match.group(4).split(","))) + + self.returns_value = self.return_type != "" and self.return_type != "void" + if self.return_type == "bool": + self.default_return_value = "false" + elif self.returns_value: + sys.stderr.write("Can only return bool: %s\n" % self.name) + sys.exit(1) + + self.agents = [option for option in self.options if "=" not in option] + + if self.returns_value and len(self.agents) > 1: + sys.stderr.write("Can only return value from a single agent: %s\n" % self.name) + sys.exit(1) + + +class Parameter(object): + def __init__(self, source): + self.options = [] + match, source = match_and_consume(r"\[(\w*)\]", source) + if match: + self.options.append(match.group(1)) + + parts = map(str.strip, source.split("=")) + self.default_value = parts[1] if len(parts) != 1 else None + + param_decl = parts[0] + min_type_tokens = 2 if re.match("(const|unsigned long) ", param_decl) else 1 + + if len(param_decl.split(" ")) > min_type_tokens: + parts = param_decl.split(" ") + self.type = " ".join(parts[:-1]) + self.name = parts[-1] + else: + self.type = param_decl + self.name = build_param_name(self.type) + + self.value = self.name + self.is_prp = re.match(r"PassRefPtr<", param_decl) is not None + if self.is_prp: + self.name = "prp" + self.name[0].upper() + self.name[1:] + self.inner_type = re.match(r"PassRefPtr<(.+)>", param_decl).group(1) + + if self.type[-1] == "*" and "char" not in self.type: + self.member_type = "Member<%s>" % self.type[:-1] + else: + self.member_type = self.type + + +def build_param_name(param_type): + base_name = re.match(r"(const |PassRefPtr<)?(\w*)", param_type).group(2) + return "param" + base_name + + +cmdline_parser = optparse.OptionParser() +cmdline_parser.add_option("--output_dir") +cmdline_parser.add_option("--template_dir") + +try: + arg_options, arg_values = cmdline_parser.parse_args() + if len(arg_values) != 1: + raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values)) + input_path = arg_values[0] + output_dirpath = arg_options.output_dir + if not output_dirpath: + raise Exception("Output directory must be specified") +except Exception: + # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html + exc = sys.exc_info()[1] + sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) + sys.stderr.write("Usage: <script> --output_dir <output_dir> InstrumentingProbes.idl\n") + exit(1) + +jinja_env = initialize_jinja_env(output_dirpath) +fin = open(input_path, "r") +files = load_model_from_idl(fin.read()) +fin.close() +all_agents = set() + +for f in files: + for declaration in f.declarations: + for agent in declaration.agents: + all_agents.add(agent) + +template_context = { + "files": files, + "agents": all_agents, + "input_file": os.path.basename(input_path) +} +cpp_template = jinja_env.get_template("/InstrumentingProbesImpl_cpp.template") +cpp_file = open(output_dirpath + "/InstrumentingProbesImpl.cpp", "w") +cpp_file.write(cpp_template.render(template_context)) +cpp_file.close() + +agents_h_template = jinja_env.get_template("/InstrumentingAgents_h.template") +agents_h_file = open(output_dirpath + "/InstrumentingAgents.h", "w") +agents_h_file.write(agents_h_template.render(template_context)) +agents_h_file.close() + +for f in files: + template_context["file"] = f + h_template = jinja_env.get_template("/InstrumentingProbesImpl_h.template") + h_file = open(output_dirpath + "/" + f.name + "Inl.h", "w") + h_file.write(h_template.render(template_context)) + h_file.close()
diff --git a/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_cpp.template b/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_cpp.template new file mode 100644 index 0000000..047dad1 --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_cpp.template
@@ -0,0 +1,114 @@ +// This file is generated from {{input_file}} + +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +{% for file in files %} +#include "{{file.header_name}}.h" +{% endfor %} +#include "InstrumentingAgents.h" +#include "core/CoreExport.h" +{% for agent in agents %} +{% set class_name = agent | agent_name_to_class %} +{% if class_name == "PerformanceMonitor" %} +#include "core/frame/PerformanceMonitor.h" +{% else %} +#include "core/inspector/{{class_name}}.h" +{% endif %} +{% endfor %} + +namespace blink { + +InstrumentingAgents::InstrumentingAgents() {} + +{% for agent in agents %} +{% set class_name = agent | agent_name_to_class %} +{% set getter_name = class_name | to_lower_case %} +void InstrumentingAgents::add{{class_name}}({{class_name}}* agent) { + m_{{getter_name}}s.insert(agent); + m_has{{class_name}}s = true; +} + +void InstrumentingAgents::remove{{class_name}}({{class_name}}* agent) { + m_{{getter_name}}s.erase(agent); + m_has{{class_name}}s = !m_{{getter_name}}s.isEmpty(); +} + +{% endfor -%} + +DEFINE_TRACE(InstrumentingAgents) +{ +{% for agent in agents %} +{% set getter_name = agent | agent_name_to_class | to_lower_case %} + visitor->trace(m_{{getter_name}}s); +{% endfor %} +} + +namespace probe { +{% macro params_list(probe) -%} +{%- for param in probe.params %} +{{param.type}} {{param.name}} +{%- if not loop.last %}, {% endif -%} +{%- endfor -%} +{%- endmacro %} + +{% macro probe_body(probe, common_name) %} +{% set agent_probe_name = common_name or probe.name %} + InstrumentingAgents* agents = instrumentingAgentsFor({{probe.params[0].name}}); + if (!agents) + return {{probe.default_return_value}}; +{% for param in probe.params %} +{% if param.is_prp %} + RefPtr<{{param.inner_type}}> {{param.value}} = {{param.name}}; +{% endif %} +{% endfor %} +{% set maybe_return = "return " if probe.returns_value else "" %} +{% for agent in probe.agents %} +{% set class_name = agent | agent_name_to_class %} + if (agents->has{{class_name}}s()) { + for ({{class_name}}* agent : agents->{{ class_name | to_lower_case }}s()) + {{maybe_return}}agent->{{agent_probe_name}}({{caller()}}); + } +{% endfor %} +{% if probe.default_return_value %} + return {{probe.default_return_value}}; +{% endif %} +{% endmacro -%} + +{% for file in files %} +{% for probe in file.declarations %} +{% if probe.is_scoped %} +{{probe.name}}::{{probe.name}}({{ params_list(probe) }}) : +{% for param in probe.params %} + {{param.name}}({{param.name}}) +{%- if not loop.last %}, +{% endif %} +{% endfor %} { +{% call probe_body(probe, "will") %}*this{% endcall %} +} + +{{probe.name}}::~{{probe.name}}() { +{% call probe_body(probe, "did") %}*this{% endcall %} +} + +{% else -%} + +CORE_EXPORT {{probe.return_type}} {{probe.name}}({{ params_list(probe) }}) { +{% call probe_body(probe, "") %} +{%- for param in probe.params %} +{%- if not loop.first or "Keep" in param.options -%} +{{param.value}} +{%- if not loop.last %}, {% endif -%} +{%- endif -%} +{%- endfor %} +{%- endcall %} +} + +{% endif %} +{% endfor %} +{% endfor %} + +} // namespace probe +} // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_h.template b/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_h.template new file mode 100644 index 0000000..d7e2cd0 --- /dev/null +++ b/third_party/WebKit/Source/core/inspector/InstrumentingProbesImpl_h.template
@@ -0,0 +1,55 @@ +// This file is generated from {{input_file}} + +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef {{file.header_name}}_h +#define {{file.header_name}}_h + +{% for include in file.includes %} +{{include}} +{% endfor %} + +namespace blink { + +{% for forward_decl in file.forward_declarations %} +{{forward_decl}} +{% endfor %} + +namespace probe { +{% for probe in file.declarations %} + +{%- macro params_decl(probe) %} +{%- for param in probe.params %} +{{ param.type }} +{%- if param.default_value %} = {{ param.default_value }} +{%- endif %} +{%- if not loop.last %}, {% endif %} +{%- endfor %} +{%- endmacro -%} + +{% if probe.is_scoped %} + + +class CORE_EXPORT {{probe.name}} : public ProbeBase { + STACK_ALLOCATED() + public: + explicit {{probe.name}}({{ params_decl(probe) }}); + ~{{probe.name}}(); +{% for param in probe.params %} + {{param.member_type}} {{param.name}}; +{% endfor %} +}; +{%- else %} + +CORE_EXPORT {{probe.return_type}} {{probe.name}}({{ params_decl(probe) }}); + +{%- endif %} +{%- endfor %} + + +} // namespace probe +} // namespace blink + +#endif // !defined({{file.header_name}}_h)
diff --git a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp index 184bb08..53fb54ed 100644 --- a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp +++ b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp
@@ -326,8 +326,8 @@ LocalFrame* frame = WeakIdentifierMap<LocalFrame>::lookup(contextGroupId); if (!frame) return; - if (frame->host()) - frame->host()->consoleMessageStorage().clear(); + if (frame->page()) + frame->page()->consoleMessageStorage().clear(); } v8::MaybeLocal<v8::Value> MainThreadDebugger::memoryInfo(
diff --git a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp index b5147ea3..aa6fa92 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp +++ b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
@@ -33,6 +33,7 @@ #include "core/InstrumentingAgents.h" #include "core/inspector/InspectorInstrumentation.h" #include "core/inspector/InspectorLogAgent.h" +#include "core/inspector/InspectorTraceEvents.h" #include "core/inspector/WorkerThreadDebugger.h" #include "core/inspector/protocol/Protocol.h" #include "core/workers/WorkerBackingThread.h" @@ -54,7 +55,9 @@ WorkerThreadDebugger* debugger) : m_debugger(debugger), m_thread(thread), - m_instrumentingAgents(new InstrumentingAgents()) {} + m_instrumentingAgents(new InstrumentingAgents()) { + m_instrumentingAgents->addInspectorTraceEvents(new InspectorTraceEvents()); +} WorkerInspectorController::~WorkerInspectorController() { DCHECK(!m_thread);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index dc258c45..c5cc0e4 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -553,7 +553,7 @@ isTableCaption() || isFieldset() || isWritingModeRoot() || isDocumentElement() || isColumnSpanAll() || isGridItem() || style()->containsPaint() || style()->containsLayout() || - isSVGForeignObject() || style()->display() == EDisplay::FlowRoot; + isSVGForeignObject() || style()->display() == EDisplay::kFlowRoot; } static inline bool changeInAvailableLogicalHeightAffectsChild( @@ -2013,12 +2013,12 @@ // anonymous logic ? EDisplay newDisplay; LayoutBlock* newBox = nullptr; - if (display == EDisplay::Flex || display == EDisplay::InlineFlex) { + if (display == EDisplay::kFlex || display == EDisplay::kInlineFlex) { newBox = LayoutFlexibleBox::createAnonymous(&parent->document()); - newDisplay = EDisplay::Flex; + newDisplay = EDisplay::kFlex; } else { newBox = LayoutBlockFlow::createAnonymous(&parent->document()); - newDisplay = EDisplay::Block; + newDisplay = EDisplay::kBlock; } RefPtr<ComputedStyle> newStyle =
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h index 7b4fdaf..49de48e4 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -221,8 +221,8 @@ static LayoutBlock* createAnonymousWithParentAndDisplay( const LayoutObject*, - EDisplay = EDisplay::Block); - LayoutBlock* createAnonymousBlock(EDisplay display = EDisplay::Block) const { + EDisplay = EDisplay::kBlock); + LayoutBlock* createAnonymousBlock(EDisplay display = EDisplay::kBlock) const { return createAnonymousWithParentAndDisplay(this, display); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index 06f862d..f5db6a1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -30,9 +30,11 @@ #include "core/layout/LayoutBlockFlow.h" +#include <memory> #include "core/editing/Editor.h" #include "core/frame/FrameView.h" #include "core/frame/LocalFrame.h" +#include "core/frame/UseCounter.h" #include "core/html/HTMLDialogElement.h" #include "core/layout/HitTestLocation.h" #include "core/layout/LayoutAnalyzer.h" @@ -52,7 +54,6 @@ #include "core/paint/PaintLayer.h" #include "platform/RuntimeEnabledFeatures.h" #include "wtf/PtrUtil.h" -#include <memory> namespace blink { @@ -4218,6 +4219,7 @@ styleRef()); case PagedFlowThread: // Paged overflow is currently done using the multicol implementation. + UseCounter::count(document(), UseCounter::CSSOverflowPaged); return LayoutPagedFlowThread::createAnonymous(document(), styleRef()); default: ASSERT_NOT_REACHED();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 2d85a29..da3c689e 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -3212,7 +3212,7 @@ // non-anonymous. if (containingBlock->isAnonymous()) { EDisplay display = containingBlock->styleRef().display(); - return display == EDisplay::Block || display == EDisplay::InlineBlock; + return display == EDisplay::kBlock || display == EDisplay::kInlineBlock; } // For quirks mode, we skip most auto-height containing blocks when computing @@ -4757,7 +4757,7 @@ return shouldBeConsideredAsReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated() || style()->containsPaint() || style()->containsLayout() || - style()->display() == EDisplay::FlowRoot; + style()->display() == EDisplay::kFlowRoot; } bool LayoutBox::hasNonCompositedScrollbars() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h index 37084cfc..aca950df 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -1088,7 +1088,7 @@ // Returns the intersection of all overflow clips which apply. virtual LayoutRect overflowClipRect( const LayoutPoint& location, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize) const; LayoutRect clipRect(const LayoutPoint& location) const; // Returns the combination of overflow clip, contain: paint clip and CSS clip @@ -1445,7 +1445,7 @@ void excludeScrollbars( LayoutRect&, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize) const; LayoutUnit containingBlockLogicalWidthForPositioned( const LayoutBoxModelObject* containingBlock,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp index 9d85fac9..1076826b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -316,10 +316,10 @@ (parent() != containingBlock()) && (styleRef().position() == oldStyle->position()) && (styleRef().originalDisplay() != oldStyle->originalDisplay()) && - ((styleRef().originalDisplay() == EDisplay::Block) || - (styleRef().originalDisplay() == EDisplay::InlineBlock)) && - ((oldStyle->originalDisplay() == EDisplay::Block) || - (oldStyle->originalDisplay() == EDisplay::InlineBlock))) + ((styleRef().originalDisplay() == EDisplay::kBlock) || + (styleRef().originalDisplay() == EDisplay::kInlineBlock)) && + ((oldStyle->originalDisplay() == EDisplay::kBlock) || + (oldStyle->originalDisplay() == EDisplay::kInlineBlock))) parent()->setNeedsLayout(LayoutInvalidationReason::ChildChanged, MarkContainerChain);
diff --git a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp index 754f64a..fc8de4fd 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
@@ -103,7 +103,7 @@ fullscreenStyle->setFontDescription(FontDescription()); fullscreenStyle->font().update(nullptr); - fullscreenStyle->setDisplay(EDisplay::Flex); + fullscreenStyle->setDisplay(EDisplay::kFlex); fullscreenStyle->setJustifyContentPosition(ContentPositionCenter); // TODO (lajava): Since the FullScrenn layout object is anonymous, its Default // Alignment (align-items) value can't be used to resolve its children Self
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index 4a8cf22..c6512dd 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -347,7 +347,7 @@ // them in a clone of this object. RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay( - containingBlock()->styleRef(), EDisplay::Block); + containingBlock()->styleRef(), EDisplay::kBlock); // If inside an inline affected by in-flow positioning the block needs to be // affected by it too. Giving the block a layer like this allows it to
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp index 0bec7de..289011e3 100644 --- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
@@ -56,7 +56,7 @@ LayoutMultiColumnFlowThread* layoutObject = new LayoutMultiColumnFlowThread(); layoutObject->setDocumentForAnonymous(&document); layoutObject->setStyle(ComputedStyle::createAnonymousStyleWithDisplay( - parentStyle, EDisplay::Block)); + parentStyle, EDisplay::kBlock)); return layoutObject; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp index 6194d7a..c467325 100644 --- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
@@ -46,7 +46,7 @@ LayoutMultiColumnSet* layoutObject = new LayoutMultiColumnSet(&flowThread); layoutObject->setDocumentForAnonymous(&document); layoutObject->setStyle(ComputedStyle::createAnonymousStyleWithDisplay( - parentStyle, EDisplay::Block)); + parentStyle, EDisplay::kBlock)); return layoutObject; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp index 4ea37764..805d8f8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp
@@ -29,7 +29,7 @@ newSpanner->setDocumentForAnonymous(&document); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parentStyle, - EDisplay::Block); + EDisplay::kBlock); copyMarginProperties(*newStyle, layoutObjectInFlowThread.styleRef()); newSpanner->setStyle(newStyle); return newSpanner;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index fc01370..2f05826 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -174,43 +174,43 @@ } switch (style.display()) { - case EDisplay::None: - case EDisplay::Contents: + case EDisplay::kNone: + case EDisplay::kContents: return nullptr; - case EDisplay::Inline: + case EDisplay::kInline: return new LayoutInline(element); - case EDisplay::Block: - case EDisplay::FlowRoot: - case EDisplay::InlineBlock: + case EDisplay::kBlock: + case EDisplay::kFlowRoot: + case EDisplay::kInlineBlock: if (RuntimeEnabledFeatures::layoutNGEnabled()) return new LayoutNGBlockFlow(element); return new LayoutBlockFlow(element); - case EDisplay::ListItem: + case EDisplay::kListItem: return new LayoutListItem(element); - case EDisplay::Table: - case EDisplay::InlineTable: + case EDisplay::kTable: + case EDisplay::kInlineTable: return new LayoutTable(element); - case EDisplay::TableRowGroup: - case EDisplay::TableHeaderGroup: - case EDisplay::TableFooterGroup: + case EDisplay::kTableRowGroup: + case EDisplay::kTableHeaderGroup: + case EDisplay::kTableFooterGroup: return new LayoutTableSection(element); - case EDisplay::TableRow: + case EDisplay::kTableRow: return new LayoutTableRow(element); - case EDisplay::TableColumnGroup: - case EDisplay::TableColumn: + case EDisplay::kTableColumnGroup: + case EDisplay::kTableColumn: return new LayoutTableCol(element); - case EDisplay::TableCell: + case EDisplay::kTableCell: return new LayoutTableCell(element); - case EDisplay::TableCaption: + case EDisplay::kTableCaption: return new LayoutTableCaption(element); - case EDisplay::WebkitBox: - case EDisplay::WebkitInlineBox: + case EDisplay::kWebkitBox: + case EDisplay::kWebkitInlineBox: return new LayoutDeprecatedFlexibleBox(*element); - case EDisplay::Flex: - case EDisplay::InlineFlex: + case EDisplay::kFlex: + case EDisplay::kInlineFlex: return new LayoutFlexibleBox(element); - case EDisplay::Grid: - case EDisplay::InlineGrid: + case EDisplay::kGrid: + case EDisplay::kInlineGrid: return new LayoutGrid(element); } @@ -1925,6 +1925,12 @@ if (oldStyle && oldStyle->styleType() == PseudoIdNone) applyPseudoStyleChanges(*oldStyle); + + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() && oldStyle && + oldStyle->usedTransformStyle3D() != styleRef().usedTransformStyle3D()) { + // Change of transform-style may affect descendant transform property nodes. + setSubtreeNeedsPaintPropertyUpdate(); + } } void LayoutObject::applyPseudoStyleChanges(const ComputedStyle& oldStyle) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index 40dee15..f9a49f8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -713,8 +713,9 @@ // LayoutBlock having a BLOCK or BOX display. Other classes such as // LayoutTextFragment are not LayoutBlocks and will return false. // See https://bugs.webkit.org/show_bug.cgi?id=56709. - return isAnonymous() && (style()->display() == EDisplay::Block || - style()->display() == EDisplay::WebkitBox) && + return isAnonymous() && + (style()->display() == EDisplay::kBlock || + style()->display() == EDisplay::kWebkitBox) && style()->styleType() == PseudoIdNone && isLayoutBlock() && !isListMarker() && !isLayoutFlowThread() && !isLayoutMultiColumnSet() && !isLayoutFullScreen() &&
diff --git a/third_party/WebKit/Source/core/layout/LayoutPagedFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutPagedFlowThread.cpp index d707417..41bc1b5 100644 --- a/third_party/WebKit/Source/core/layout/LayoutPagedFlowThread.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutPagedFlowThread.cpp
@@ -14,7 +14,7 @@ LayoutPagedFlowThread* pagedFlowThread = new LayoutPagedFlowThread(); pagedFlowThread->setDocumentForAnonymous(&document); pagedFlowThread->setStyle(ComputedStyle::createAnonymousStyleWithDisplay( - parentStyle, EDisplay::Block)); + parentStyle, EDisplay::kBlock)); return pagedFlowThread; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutRubyRun.cpp b/third_party/WebKit/Source/core/layout/LayoutRubyRun.cpp index c38bb42..af598c4 100644 --- a/third_party/WebKit/Source/core/layout/LayoutRubyRun.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutRubyRun.cpp
@@ -182,7 +182,7 @@ LayoutRubyBase* layoutObject = LayoutRubyBase::createAnonymous(&document()); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(styleRef(), - EDisplay::Block); + EDisplay::kBlock); newStyle->setTextAlign(ETextAlign::kCenter); // FIXME: use WEBKIT_CENTER? layoutObject->setStyle(std::move(newStyle)); return layoutObject; @@ -195,7 +195,7 @@ rr->setDocumentForAnonymous(&parentRuby->document()); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parentRuby->styleRef(), - EDisplay::InlineBlock); + EDisplay::kInlineBlock); rr->setStyle(std::move(newStyle)); return rr; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp index 246e8de7..6670d07 100644 --- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
@@ -228,9 +228,9 @@ : PassRefPtr<ComputedStyle>(nullptr); bool needLayoutObject = - !destroy && partStyle && partStyle->display() != EDisplay::None; + !destroy && partStyle && partStyle->display() != EDisplay::kNone; - if (needLayoutObject && partStyle->display() != EDisplay::Block) { + if (needLayoutObject && partStyle->display() != EDisplay::kBlock) { // See if we are a button that should not be visible according to OS // settings. WebScrollbarButtonsPlacement buttonsPlacement = theme().buttonsPlacement();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp index ea658b4..a60abf0d 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -120,9 +120,9 @@ // Return true if 'object' can't exist in an anonymous table without being // wrapped in a table section box. EDisplay display = object->style()->display(); - return display != EDisplay::TableCaption && - display != EDisplay::TableColumnGroup && - display != EDisplay::TableColumn; + return display != EDisplay::kTableCaption && + display != EDisplay::kTableColumnGroup && + display != EDisplay::kTableColumn; } void LayoutTable::addChild(LayoutObject* child, LayoutObject* beforeChild) { @@ -135,7 +135,7 @@ wrapInAnonymousSection = false; } else if (child->isTableSection()) { switch (child->style()->display()) { - case EDisplay::TableHeaderGroup: + case EDisplay::kTableHeaderGroup: resetSectionPointerIfNotBefore(m_head, beforeChild); if (!m_head) { m_head = toLayoutTableSection(child); @@ -146,7 +146,7 @@ } wrapInAnonymousSection = false; break; - case EDisplay::TableFooterGroup: + case EDisplay::kTableFooterGroup: resetSectionPointerIfNotBefore(m_foot, beforeChild); if (!m_foot) { m_foot = toLayoutTableSection(child); @@ -154,7 +154,7 @@ break; } // Fall through. - case EDisplay::TableRowGroup: + case EDisplay::kTableRowGroup: resetSectionPointerIfNotBefore(m_firstBody, beforeChild); if (!m_firstBody) m_firstBody = toLayoutTableSection(child); @@ -1081,11 +1081,11 @@ for (LayoutObject* child = firstChild(); child; child = nextSibling) { nextSibling = child->nextSibling(); switch (child->style()->display()) { - case EDisplay::TableColumn: - case EDisplay::TableColumnGroup: + case EDisplay::kTableColumn: + case EDisplay::kTableColumnGroup: m_hasColElements = true; break; - case EDisplay::TableHeaderGroup: + case EDisplay::kTableHeaderGroup: if (child->isTableSection()) { LayoutTableSection* section = toLayoutTableSection(child); if (!m_head) @@ -1095,7 +1095,7 @@ section->recalcCellsIfNeeded(); } break; - case EDisplay::TableFooterGroup: + case EDisplay::kTableFooterGroup: if (child->isTableSection()) { LayoutTableSection* section = toLayoutTableSection(child); if (!m_foot) @@ -1105,7 +1105,7 @@ section->recalcCellsIfNeeded(); } break; - case EDisplay::TableRowGroup: + case EDisplay::kTableRowGroup: if (child->isTableSection()) { LayoutTableSection* section = toLayoutTableSection(child); if (!m_firstBody) @@ -1645,7 +1645,7 @@ RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay( parent->styleRef(), - parent->isLayoutInline() ? EDisplay::InlineTable : EDisplay::Table); + parent->isLayoutInline() ? EDisplay::kInlineTable : EDisplay::kTable); LayoutTable* newTable = new LayoutTable(nullptr); newTable->setDocumentForAnonymous(&parent->document()); newTable->setStyle(std::move(newStyle));
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.h b/third_party/WebKit/Source/core/layout/LayoutTable.h index 26b7755..d5bc8c92 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTable.h +++ b/third_party/WebKit/Source/core/layout/LayoutTable.h
@@ -508,7 +508,8 @@ LayoutRect overflowClipRect( const LayoutPoint& location, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; void addOverflowFromChildren() override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp index 4146da6..f10f6ce 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -479,7 +479,7 @@ void LayoutTableCell::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { - DCHECK_EQ(style()->display(), EDisplay::TableCell); + DCHECK_EQ(style()->display(), EDisplay::kTableCell); LayoutBlockFlow::styleDidChange(diff, oldStyle); setHasBoxDecorationBackground(true); @@ -1438,7 +1438,7 @@ LayoutTableCell::createAnonymous(&parent->document()); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parent->styleRef(), - EDisplay::TableCell); + EDisplay::kTableCell); newCell->setStyle(std::move(newStyle)); return newCell; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp index ba923455..eefe5b6 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCol.cpp
@@ -43,8 +43,8 @@ void LayoutTableCol::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { - DCHECK(style()->display() == EDisplay::TableColumn || - style()->display() == EDisplay::TableColumnGroup); + DCHECK(style()->display() == EDisplay::kTableColumn || + style()->display() == EDisplay::kTableColumnGroup); LayoutTableBoxComponent::styleDidChange(diff, oldStyle); @@ -102,7 +102,7 @@ bool LayoutTableCol::isChildAllowed(LayoutObject* child, const ComputedStyle& style) const { // We cannot use isTableColumn here as style() may return 0. - return child->isLayoutTableCol() && style.display() == EDisplay::TableColumn; + return child->isLayoutTableCol() && style.display() == EDisplay::kTableColumn; } bool LayoutTableCol::canHaveChildren() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCol.h b/third_party/WebKit/Source/core/layout/LayoutTableCol.h index c8d0bd8..a6244de 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCol.h +++ b/third_party/WebKit/Source/core/layout/LayoutTableCol.h
@@ -69,10 +69,10 @@ bool isTableColumnGroupWithColumnChildren() { return firstChild(); } bool isTableColumn() const { - return style()->display() == EDisplay::TableColumn; + return style()->display() == EDisplay::kTableColumn; } bool isTableColumnGroup() const { - return style()->display() == EDisplay::TableColumnGroup; + return style()->display() == EDisplay::kTableColumnGroup; } LayoutTableCol* enclosingColumnGroup() const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp index ec17e6c..3184ad5 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
@@ -54,7 +54,7 @@ void LayoutTableRow::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { - DCHECK_EQ(style()->display(), EDisplay::TableRow); + DCHECK_EQ(style()->display(), EDisplay::kTableRow); LayoutTableBoxComponent::styleDidChange(diff, oldStyle); propagateStyleToAnonymousChildren(); @@ -278,7 +278,7 @@ LayoutTableRow* newRow = LayoutTableRow::createAnonymous(&parent->document()); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parent->styleRef(), - EDisplay::TableRow); + EDisplay::kTableRow); newRow->setStyle(std::move(newStyle)); return newRow; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp index c272289..732fa1a 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -115,9 +115,9 @@ void LayoutTableSection::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { - DCHECK(style()->display() == EDisplay::TableFooterGroup || - style()->display() == EDisplay::TableRowGroup || - style()->display() == EDisplay::TableHeaderGroup); + DCHECK(style()->display() == EDisplay::kTableFooterGroup || + style()->display() == EDisplay::kTableRowGroup || + style()->display() == EDisplay::kTableHeaderGroup); LayoutTableBoxComponent::styleDidChange(diff, oldStyle); propagateStyleToAnonymousChildren(); @@ -1846,7 +1846,7 @@ const LayoutObject* parent) { RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parent->styleRef(), - EDisplay::TableRowGroup); + EDisplay::kTableRowGroup); LayoutTableSection* newSection = new LayoutTableSection(nullptr); newSection->setDocumentForAnonymous(&parent->document()); newSection->setStyle(std::move(newStyle));
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp index 3a7bf40..ffd9b28 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp
@@ -92,7 +92,7 @@ RefPtr<ComputedStyle> textBlockStyle = ComputedStyle::create(); textBlockStyle->inheritFrom(startStyle); adjustInnerEditorStyle(*textBlockStyle); - textBlockStyle->setDisplay(EDisplay::Block); + textBlockStyle->setDisplay(EDisplay::kBlock); textBlockStyle->setUnique(); return textBlockStyle.release();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp index f0ea860..4df23996 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp
@@ -326,7 +326,7 @@ logicalHeight.getFloatValue() > computedLineHeight)) textBlockStyle->setLineHeight(ComputedStyle::initialLineHeight()); - textBlockStyle->setDisplay(EDisplay::Block); + textBlockStyle->setDisplay(EDisplay::kBlock); textBlockStyle->setUnique(); if (inputElement()->shouldRevealPassword()) @@ -337,7 +337,7 @@ textBlockStyle->setOverflowY(EOverflow::kScroll); RefPtr<ComputedStyle> noScrollbarStyle = ComputedStyle::create(); noScrollbarStyle->setStyleType(PseudoIdScrollbar); - noScrollbarStyle->setDisplay(EDisplay::None); + noScrollbarStyle->setDisplay(EDisplay::kNone); textBlockStyle->addCachedPseudoStyle(noScrollbarStyle); textBlockStyle->setHasPseudoStyle(PseudoIdScrollbar);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextTrackContainer.cpp b/third_party/WebKit/Source/core/layout/LayoutTextTrackContainer.cpp index 67532156..065f95a6 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextTrackContainer.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextTrackContainer.cpp
@@ -37,7 +37,7 @@ void LayoutTextTrackContainer::layout() { LayoutBlockFlow::layout(); - if (style()->display() == EDisplay::None) + if (style()->display() == EDisplay::kNone) return; DeprecatedScheduleStyleRecalcDuringLayout marker(
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp index c42b215..cda01b9a 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
@@ -82,20 +82,20 @@ // Force inline and table display styles to be inline-block (except for table- // which is block) ControlPart part = style.appearance(); - if (style.display() == EDisplay::Inline || - style.display() == EDisplay::InlineTable || - style.display() == EDisplay::TableRowGroup || - style.display() == EDisplay::TableHeaderGroup || - style.display() == EDisplay::TableFooterGroup || - style.display() == EDisplay::TableRow || - style.display() == EDisplay::TableColumnGroup || - style.display() == EDisplay::TableColumn || - style.display() == EDisplay::TableCell || - style.display() == EDisplay::TableCaption) - style.setDisplay(EDisplay::InlineBlock); - else if (style.display() == EDisplay::ListItem || - style.display() == EDisplay::Table) - style.setDisplay(EDisplay::Block); + if (style.display() == EDisplay::kInline || + style.display() == EDisplay::kInlineTable || + style.display() == EDisplay::kTableRowGroup || + style.display() == EDisplay::kTableHeaderGroup || + style.display() == EDisplay::kTableFooterGroup || + style.display() == EDisplay::kTableRow || + style.display() == EDisplay::kTableColumnGroup || + style.display() == EDisplay::kTableColumn || + style.display() == EDisplay::kTableCell || + style.display() == EDisplay::kTableCaption) + style.setDisplay(EDisplay::kInlineBlock); + else if (style.display() == EDisplay::kListItem || + style.display() == EDisplay::kTable) + style.setDisplay(EDisplay::kBlock); if (isControlStyled(style)) { if (part == MenulistPart) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.h b/third_party/WebKit/Source/core/layout/LayoutView.h index 2674d80..fccdf4bd 100644 --- a/third_party/WebKit/Source/core/layout/LayoutView.h +++ b/third_party/WebKit/Source/core/layout/LayoutView.h
@@ -173,7 +173,8 @@ LayoutRect viewRect() const override; LayoutRect overflowClipRect( const LayoutPoint& location, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; LayoutState* layoutState() const { return m_layoutState; }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h index b51a0b37..1df7eed 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
@@ -49,7 +49,7 @@ LayoutRect overflowClipRect(const LayoutPoint& location, OverlayScrollbarClipBehavior behavior = - IgnoreOverlayScrollbarSize) const { + IgnorePlatformOverlayScrollbarSize) const { return toBox()->overflowClipRect(location, behavior); }
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 183c283..c715a29 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -550,7 +550,7 @@ // FIXME: this should use cached clip rects, but this sometimes give // inaccurate results (and trips the ASSERTS in PaintLayerClipper). ClipRectsContext clipRectsContext(compositingAncestor, UncachedClipRects, - IgnoreOverlayScrollbarSize); + IgnorePlatformOverlayScrollbarSize); clipRectsContext.setIgnoreOverflowClip(); ClipRect clipRect; @@ -1162,7 +1162,7 @@ ClipRectsContext clipRectsContext(compositingContainer, PaintingClipRectsIgnoringOverflowClip, - IgnoreOverlayScrollbarSize); + IgnorePlatformOverlayScrollbarSize); ClipRect parentClipRect; m_owningLayer.clipper(PaintLayer::DoNotUseGeometryMapper)
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h index aabab90..8831039 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h +++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
@@ -73,7 +73,8 @@ // must not apply. This change also means that gaps will exist between image // bullet list items. Even when the list bullet is an image, the line is // still considered to be immune from the quirk. - m_hasTextChildren = lineLayoutItem.style()->display() == EDisplay::ListItem; + m_hasTextChildren = + lineLayoutItem.style()->display() == EDisplay::kListItem; m_hasTextDescendants = m_hasTextChildren; }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc index d752903..a7b476f 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -36,7 +36,7 @@ bool is_in_parallel_flow = IsParallelWritingMode(parent_space.WritingMode(), child_writing_mode); - return child_style.display() == EDisplay::InlineBlock || + return child_style.display() == EDisplay::kInlineBlock || child_style.isFloating() || !is_in_parallel_flow; } @@ -163,6 +163,7 @@ const LayoutUnit float_offset, const NGLogicalOffset& from_offset, NGFloatingObject* floating_object) { + DCHECK(floating_object); auto margins = floating_object->margins; // Adjust to child's margin. LayoutUnit inline_offset = margins.inline_start; @@ -187,6 +188,7 @@ const NGLogicalOffset& from_offset, NGFloatingObject* floating_object, NGConstraintSpace* new_parent_space) { + DCHECK(floating_object); const auto* float_space = floating_object->space.get(); DCHECK(floating_object->fragment) << "Fragment cannot be null here"; @@ -220,10 +222,10 @@ // Updates the Floating Object's left offset from the provided parent_space // and {@code floating_object}'s space and margins. -void UpdateFloatingObjectLeftOffset( - const NGConstraintSpace& new_parent_space, - const Persistent<NGFloatingObject>& floating_object, - const NGLogicalOffset& float_logical_offset) { +void UpdateFloatingObjectLeftOffset(const NGConstraintSpace& new_parent_space, + const NGLogicalOffset& float_logical_offset, + NGFloatingObject* floating_object) { + DCHECK(floating_object); // TODO(glebl): We should use physical offset here. floating_object->left_offset = floating_object->original_parent_space->BfcOffset().inline_offset - @@ -250,10 +252,10 @@ original_parent_space->BfcOffset().inline_offset, bfc_block_offset}; NGLogicalOffset float_fragment_offset = PositionFloat( - origin_point, from_offset, floating_object, new_parent_space); + origin_point, from_offset, floating_object.get(), new_parent_space); builder->AddFloatingObject(floating_object, float_fragment_offset); - UpdateFloatingObjectLeftOffset(*new_parent_space, floating_object, - float_fragment_offset); + UpdateFloatingObjectLeftOffset(*new_parent_space, float_fragment_offset, + floating_object.get()); } builder->MutableUnpositionedFloats().clear(); } @@ -283,8 +285,8 @@ return true; EDisplay display = style.display(); - if (display == EDisplay::Grid || display == EDisplay::Flex || - display == EDisplay::WebkitBox) + if (display == EDisplay::kGrid || display == EDisplay::kFlex || + display == EDisplay::kWebkitBox) return true; if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode())) @@ -534,7 +536,7 @@ if (child->Type() == NGLayoutInputNode::kLegacyBlock && toNGBlockNode(child)->Style().isFloating()) { - NGFloatingObject* floating_object = new NGFloatingObject( + RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create( child_space, constraint_space_, toNGBlockNode(child)->Style(), curr_child_margins_, layout_result->PhysicalFragment().get()); builder_.AddUnpositionedFloat(floating_object);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc index 773af5f..af0c901 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -239,8 +239,9 @@ // We may still have unpositioned floats when we reach the root box. if (!layout_box_->parent()) { - for (const auto& floating_object : fragment->PositionedFloats()) { - FloatingObjectPositionedUpdated(floating_object, layout_box_); + for (const RefPtr<NGFloatingObject>& floating_object : + fragment->PositionedFloats()) { + FloatingObjectPositionedUpdated(floating_object.get(), layout_box_); } } @@ -248,10 +249,11 @@ if (child_fragment->IsPlaced()) FragmentPositionUpdated(toNGPhysicalBoxFragment(*child_fragment)); - for (const auto& floating_object : + for (const RefPtr<NGFloatingObject>& floating_object : toNGPhysicalBoxFragment(child_fragment.get())->PositionedFloats()) { FloatingObjectPositionedUpdated( - floating_object, toLayoutBox(child_fragment->GetLayoutObject())); + floating_object.get(), + toLayoutBox(child_fragment->GetLayoutObject())); } }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h b/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h index f841775..8430c5a 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h
@@ -9,30 +9,23 @@ #include "core/layout/ng/ng_block_node.h" #include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_exclusion.h" +#include "core/layout/ng/ng_physical_fragment.h" #include "core/style/ComputedStyle.h" #include "core/style/ComputedStyleConstants.h" -#include "platform/heap/Handle.h" +#include "wtf/RefPtr.h" namespace blink { -class NGPhysicalFragment; - // Struct that keeps all information needed to position floats in LayoutNG. -struct CORE_EXPORT NGFloatingObject - : public GarbageCollectedFinalized<NGFloatingObject> { - NGFloatingObject(const NGConstraintSpace* space, - const NGConstraintSpace* parent_space, - const ComputedStyle& style, - const NGBoxStrut& margins, - NGPhysicalFragment* fragment) - : space(space), - original_parent_space(parent_space), - margins(margins), - fragment(fragment) { - exclusion_type = NGExclusion::kFloatLeft; - if (style.floating() == EFloat::kRight) - exclusion_type = NGExclusion::kFloatRight; - clear_type = style.clear(); +struct CORE_EXPORT NGFloatingObject : public RefCounted<NGFloatingObject> { + public: + static RefPtr<NGFloatingObject> Create(const NGConstraintSpace* space, + const NGConstraintSpace* parent_space, + const ComputedStyle& style, + const NGBoxStrut& margins, + NGPhysicalFragment* fragment) { + return adoptRef( + new NGFloatingObject(space, parent_space, style, margins, fragment)); } // Original constraint space of the float. @@ -57,7 +50,20 @@ // would be attached. LayoutUnit left_offset; - DEFINE_INLINE_TRACE() { + private: + NGFloatingObject(const NGConstraintSpace* space, + const NGConstraintSpace* parent_space, + const ComputedStyle& style, + const NGBoxStrut& margins, + NGPhysicalFragment* fragment) + : space(space), + original_parent_space(parent_space), + margins(margins), + fragment(fragment) { + exclusion_type = NGExclusion::kFloatLeft; + if (style.floating() == EFloat::kRight) + exclusion_type = NGExclusion::kFloatRight; + clear_type = style.clear(); } };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc index cabf376d..7348e7ea 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
@@ -91,7 +91,7 @@ } NGFragmentBuilder& NGFragmentBuilder::AddFloatingObject( - NGFloatingObject* floating_object, + RefPtr<NGFloatingObject> floating_object, const NGLogicalOffset& floating_object_offset) { positioned_floats_.push_back(floating_object); floating_object_offsets_.push_back(floating_object_offset); @@ -117,8 +117,8 @@ } NGFragmentBuilder& NGFragmentBuilder::AddUnpositionedFloat( - NGFloatingObject* floating_object) { - unpositioned_floats_.push_back(floating_object); + RefPtr<NGFloatingObject> floating_object) { + unpositioned_floats_.push_back(std::move(floating_object)); return *this; } @@ -173,9 +173,6 @@ writing_mode_, direction_, physical_size, child->Size())); } - Vector<Persistent<NGFloatingObject>> positioned_floats; - positioned_floats.reserveCapacity(positioned_floats_.size()); - RefPtr<NGBreakToken> break_token; if (did_break_) { break_token = NGBlockBreakToken::create( @@ -185,11 +182,10 @@ } for (size_t i = 0; i < positioned_floats_.size(); ++i) { - Persistent<NGFloatingObject>& floating_object = positioned_floats_[i]; + RefPtr<NGFloatingObject>& floating_object = positioned_floats_[i]; NGPhysicalFragment* floating_fragment = floating_object->fragment.get(); floating_fragment->SetOffset(floating_object_offsets_[i].ConvertToPhysical( writing_mode_, direction_, physical_size, floating_fragment->Size())); - positioned_floats.push_back(floating_object); } RefPtr<NGPhysicalBoxFragment> fragment = adoptRef(new NGPhysicalBoxFragment( @@ -210,9 +206,6 @@ DCHECK(children_.isEmpty()); DCHECK(offsets_.isEmpty()); - Vector<Persistent<NGFloatingObject>> empty_unpositioned_floats; - Vector<Persistent<NGFloatingObject>> empty_positioned_floats; - return adoptRef(new NGPhysicalTextFragment( node_->GetLayoutObject(), toNGInlineNode(node_), index, start_offset, end_offset, size_.ConvertToPhysical(writing_mode_),
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h index fd11878d..f3f18eb 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
@@ -38,12 +38,13 @@ NGFragmentBuilder& AddChild(RefPtr<NGPhysicalFragment>, const NGLogicalOffset&); - NGFragmentBuilder& AddFloatingObject(NGFloatingObject*, + NGFragmentBuilder& AddFloatingObject(RefPtr<NGFloatingObject>, const NGLogicalOffset&); NGFragmentBuilder& SetBfcOffset(const NGLogicalOffset& offset); - NGFragmentBuilder& AddUnpositionedFloat(NGFloatingObject* floating_object); + NGFragmentBuilder& AddUnpositionedFloat( + RefPtr<NGFloatingObject> floating_object); // Builder has non-trivial out-of-flow descendant methods. // These methods are building blocks for implementation of @@ -103,12 +104,12 @@ unsigned end_offset); // Mutable list of floats that need to be positioned. - Vector<Persistent<NGFloatingObject>>& MutableUnpositionedFloats() { + Vector<RefPtr<NGFloatingObject>>& MutableUnpositionedFloats() { return unpositioned_floats_; } // List of floats that need to be positioned. - const Vector<Persistent<NGFloatingObject>>& UnpositionedFloats() const { + const Vector<RefPtr<NGFloatingObject>>& UnpositionedFloats() const { return unpositioned_floats_; } @@ -162,10 +163,10 @@ // Floats that need to be positioned by the next in-flow fragment that can // determine its block position in space. - Vector<Persistent<NGFloatingObject>> unpositioned_floats_; + Vector<RefPtr<NGFloatingObject>> unpositioned_floats_; Vector<NGLogicalOffset> floating_object_offsets_; - Vector<Persistent<NGFloatingObject>> positioned_floats_; + Vector<RefPtr<NGFloatingObject>> positioned_floats_; WTF::Optional<NGLogicalOffset> bfc_offset_; NGMarginStrut end_margin_strut_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc index 1954a5b..d078576 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
@@ -22,7 +22,7 @@ // [1] https://drafts.csswg.org/css-text-3/#line-break-transform // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2 unsigned next_start_offset = text_.length(); - RemoveTrailingCollapsibleSpace(&next_start_offset); + RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset); return text_.toString(); } @@ -55,8 +55,9 @@ const ComputedStyle* after_style) { // Remove if either before/after the newline is zeroWidthSpaceCharacter. UChar32 last = 0; - if (!before.isEmpty()) { - last = before[before.length() - 1]; + DCHECK(!before.isEmpty() && before[before.length() - 1] == ' '); + if (before.length() >= 2) { + last = before[before.length() - 2]; if (last == zeroWidthSpaceCharacter) return true; } @@ -111,15 +112,17 @@ items->push_back(NGLayoutInlineItem(start, end, style, layout_object)); } +static inline bool IsCollapsibleSpace(UChar c, bool preserve_newline) { + return c == spaceCharacter || c == tabulationCharacter || + (!preserve_newline && c == newlineCharacter); +} + void NGLayoutInlineItemsBuilder::Append(const String& string, const ComputedStyle* style, LayoutObject* layout_object) { if (string.isEmpty()) return; - if (has_pending_newline_) - ProcessPendingNewline(string, style); - EWhiteSpace whitespace = style->whiteSpace(); bool preserve_newline = ComputedStyle::preserveNewline(whitespace) && !is_svgtext_; @@ -128,38 +131,49 @@ if (!collapse_whitespace) { text_.append(string); - is_last_collapsible_space_ = false; + last_collapsible_space_ = CollapsibleSpace::None; } else { text_.reserveCapacity(string.length()); - for (unsigned i = 0; i < string.length(); i++) { + for (unsigned i = 0; i < string.length();) { UChar c = string[i]; - bool is_collapsible_space; if (c == newlineCharacter) { - RemoveTrailingCollapsibleSpace(&start_offset); if (preserve_newline) { + RemoveTrailingCollapsibleSpaceIfExists(&start_offset); text_.append(c); // Remove collapsible spaces immediately following a newline. - is_last_collapsible_space_ = true; + last_collapsible_space_ = CollapsibleSpace::Space; + i++; continue; } - if (i + 1 == string.length()) { - // If at the end of string, process this newline on the next Append. - has_pending_newline_ = true; + + if (last_collapsible_space_ == CollapsibleSpace::None) + text_.append(spaceCharacter); + last_collapsible_space_ = CollapsibleSpace::Newline; + i++; + continue; + } + + if (c == spaceCharacter || c == tabulationCharacter) { + if (last_collapsible_space_ == CollapsibleSpace::None) { + text_.append(spaceCharacter); + last_collapsible_space_ = CollapsibleSpace::Space; + } + i++; + continue; + } + + if (last_collapsible_space_ == CollapsibleSpace::Newline) { + RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, + style); + } + + unsigned start_of_non_space = i; + for (i++; i < string.length(); i++) { + if (IsCollapsibleSpace(string[i], false)) break; - } - if (ShouldRemoveNewline(text_, style, string, i + 1, style)) - continue; - is_collapsible_space = true; - } else { - is_collapsible_space = c == spaceCharacter || c == tabulationCharacter; } - if (!is_collapsible_space) { - text_.append(c); - is_last_collapsible_space_ = false; - } else if (!is_last_collapsible_space_) { - text_.append(spaceCharacter); - is_last_collapsible_space_ = true; - } + text_.append(string, start_of_non_space, i - start_of_non_space); + last_collapsible_space_ = CollapsibleSpace::None; } } @@ -172,49 +186,49 @@ LayoutObject* layout_object) { DCHECK(character != spaceCharacter && character != tabulationCharacter && character != newlineCharacter && character != zeroWidthSpaceCharacter); - if (has_pending_newline_) - ProcessPendingNewline(emptyString, nullptr); text_.append(character); unsigned end_offset = text_.length(); AppendItem(items_, end_offset - 1, end_offset, style, layout_object); - is_last_collapsible_space_ = false; + last_collapsible_space_ = CollapsibleSpace::None; } -void NGLayoutInlineItemsBuilder::AppendAsOpaqueToSpaceCollapsing( - UChar character) { - if (has_pending_newline_) - ProcessPendingNewline(emptyString, nullptr); +void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( + unsigned* next_start_offset, + const String& after, + unsigned after_index, + const ComputedStyle* after_style) { + DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::Newline); - text_.append(character); - unsigned end_offset = text_.length(); - AppendItem(items_, end_offset - 1, end_offset, nullptr); -} + if (text_.isEmpty() || text_[text_.length() - 1] != spaceCharacter) + return; -void NGLayoutInlineItemsBuilder::ProcessPendingNewline( - const String& string, - const ComputedStyle* style) { - DCHECK(has_pending_newline_); + const ComputedStyle* before_style = after_style; if (!items_->isEmpty()) { NGLayoutInlineItem& item = items_->back(); - if (!ShouldRemoveNewline(text_, item.Style(), string, 0, style)) { - text_.append(spaceCharacter); - item.SetEndOffset(text_.length()); - } + if (text_.length() < item.EndOffset() + 2) + before_style = item.Style(); } - // Remove spaces following a newline even when the newline was removed. - is_last_collapsible_space_ = true; - has_pending_newline_ = false; + + if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style)) + RemoveTrailingCollapsibleSpace(next_start_offset); +} + +void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( + unsigned* next_start_offset) { + if (last_collapsible_space_ != CollapsibleSpace::None && !text_.isEmpty() && + text_[text_.length() - 1] == spaceCharacter) + RemoveTrailingCollapsibleSpace(next_start_offset); } void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleSpace( unsigned* next_start_offset) { - if (!is_last_collapsible_space_ || text_.isEmpty()) - return; - DCHECK_EQ(spaceCharacter, text_[text_.length() - 1]); + DCHECK_NE(last_collapsible_space_, CollapsibleSpace::None); + DCHECK(!text_.isEmpty() && text_[text_.length() - 1] == spaceCharacter); + unsigned new_size = text_.length() - 1; text_.resize(new_size); - is_last_collapsible_space_ = false; + last_collapsible_space_ = CollapsibleSpace::None; // Adjust the last item if the removed space is already appended. if (*next_start_offset > new_size) { @@ -233,8 +247,7 @@ void NGLayoutInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style, UChar ltr, UChar rtl) { - AppendAsOpaqueToSpaceCollapsing( - style->direction() == TextDirection::kRtl ? rtl : ltr); + Append(style->direction() == TextDirection::kRtl ? rtl : ltr); } void NGLayoutInlineItemsBuilder::EnterBlock(const ComputedStyle* style) { @@ -273,11 +286,11 @@ Enter(node, popDirectionalIsolateCharacter); break; case UnicodeBidi::kPlaintext: - AppendAsOpaqueToSpaceCollapsing(firstStrongIsolateCharacter); + Append(firstStrongIsolateCharacter); Enter(node, popDirectionalIsolateCharacter); break; case UnicodeBidi::kIsolateOverride: - AppendAsOpaqueToSpaceCollapsing(firstStrongIsolateCharacter); + Append(firstStrongIsolateCharacter); AppendBidiControl(style, leftToRightOverrideCharacter, rightToLeftOverrideCharacter); Enter(node, popDirectionalIsolateCharacter); @@ -303,7 +316,7 @@ void NGLayoutInlineItemsBuilder::Exit(LayoutObject* node) { while (!exits_.isEmpty() && exits_.back().node == node) { - AppendAsOpaqueToSpaceCollapsing(exits_.back().character); + Append(exits_.back().character); exits_.pop_back(); } }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h index adeb6f9..4fe4e42 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h
@@ -61,11 +61,7 @@ // LayoutObject. void Append(UChar, const ComputedStyle* = nullptr, LayoutObject* = nullptr); - // Append a character. - // The character is opaque to space collapsing that spaces before this - // character and after this character can collapse as if this character does - // not exist. - void AppendAsOpaqueToSpaceCollapsing(UChar); + // Append a Bidi control character, for LTR or RTL depends on the style. void AppendBidiControl(const ComputedStyle*, UChar ltr, UChar rtl); void EnterBlock(const ComputedStyle*); @@ -83,8 +79,9 @@ } OnExitNode; Vector<OnExitNode> exits_; - bool is_last_collapsible_space_ = true; - bool has_pending_newline_ = false; + enum class CollapsibleSpace { None, Space, Newline }; + + CollapsibleSpace last_collapsible_space_ = CollapsibleSpace::Space; bool is_svgtext_ = false; bool has_bidi_controls_ = false; @@ -95,8 +92,14 @@ void ProcessPendingNewline(const String&, const ComputedStyle*); // Removes the collapsible space at the end of |text_| if exists. + void RemoveTrailingCollapsibleSpaceIfExists(unsigned*); void RemoveTrailingCollapsibleSpace(unsigned*); + void RemoveTrailingCollapsibleNewlineIfNeeded(unsigned*, + const String&, + unsigned, + const ComputedStyle*); + void Enter(LayoutObject*, UChar); void Exit(LayoutObject*); };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder_test.cc index b878a5a..3331e7c 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder_test.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder_test.cc
@@ -97,15 +97,22 @@ } TEST_F(NGLayoutInlineItemsBuilderTest, CollapseNewLines) { - String input("text\ntext \n text"); - String collapsed("text text text"); + String input("text\ntext \n text\n\ntext"); + String collapsed("text text text text"); TestWhitespaceValue(collapsed, input, EWhiteSpace::kNormal); TestWhitespaceValue(collapsed, input, EWhiteSpace::kNowrap); - TestWhitespaceValue("text\ntext\ntext", input, EWhiteSpace::kPreLine); + TestWhitespaceValue("text\ntext\ntext\n\ntext", input, EWhiteSpace::kPreLine); TestWhitespaceValue(input, input, EWhiteSpace::kPre); TestWhitespaceValue(input, input, EWhiteSpace::kPreWrap); } +TEST_F(NGLayoutInlineItemsBuilderTest, CollapseNewlinesAsSpaces) { + EXPECT_EQ("text text", TestAppend("text\ntext")); + EXPECT_EQ("text text", TestAppend("text\n\ntext")); + EXPECT_EQ("text text", TestAppend("text \n\n text")); + EXPECT_EQ("text text", TestAppend("text \n \n text")); +} + TEST_F(NGLayoutInlineItemsBuilderTest, CollapseAcrossElements) { EXPECT_EQ("text text", TestAppend("text ", " text")) << "Spaces are collapsed even when across elements."; @@ -175,9 +182,6 @@ } TEST_F(NGLayoutInlineItemsBuilderTest, CollapseZeroWidthSpaces) { - EXPECT_EQ("text text", TestAppend("text\ntext")) - << "Newline is converted to a space."; - EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B\ntext")) << "Newline is removed if the character before is ZWS."; EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\n\u200Btext")) @@ -224,12 +228,16 @@ EXPECT_EQ(String(u"Hello \uFFFC World"), builder.ToString()); } -TEST_F(NGLayoutInlineItemsBuilderTest, AppendAsOpaqueToSpaceCollapsing) { +TEST_F(NGLayoutInlineItemsBuilderTest, CollapseNewlineAfterObject) { NGLayoutInlineItemsBuilder builder(&items_); - builder.Append("Hello ", style_.get()); - builder.AppendAsOpaqueToSpaceCollapsing(firstStrongIsolateCharacter); - builder.Append(" World", style_.get()); - EXPECT_EQ(String(u"Hello \u2068World"), builder.ToString()); + builder.Append(objectReplacementCharacter); + builder.Append("\n", style_.get()); + builder.Append(objectReplacementCharacter); + EXPECT_EQ(String(u"\uFFFC \uFFFC"), builder.ToString()); + EXPECT_EQ(3u, items_.size()); + EXPECT_EQ(nullptr, items_[0].Style()); + EXPECT_EQ(style_.get(), items_[1].Style()); + EXPECT_EQ(nullptr, items_[2].Style()); } TEST_F(NGLayoutInlineItemsBuilderTest, AppendEmptyString) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc index 5a45423..c70b970 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
@@ -4,8 +4,6 @@ #include "core/layout/ng/ng_layout_result.h" -#include "core/layout/ng/ng_floating_object.h" - namespace blink { NGLayoutResult::NGLayoutResult( @@ -13,10 +11,12 @@ PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>& out_of_flow_descendants, Vector<NGStaticPosition> out_of_flow_positions, - Vector<Persistent<NGFloatingObject>>& unpositioned_floats) + Vector<RefPtr<NGFloatingObject>>& unpositioned_floats) : physical_fragment_(physical_fragment), + layout_object_(nullptr), out_of_flow_descendants_(out_of_flow_descendants), - out_of_flow_positions_(out_of_flow_positions), - unpositioned_floats_(unpositioned_floats) {} + out_of_flow_positions_(out_of_flow_positions) { + unpositioned_floats_.swap(unpositioned_floats); +} } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h index 3ec77699..64689633 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
@@ -7,6 +7,7 @@ #include "core/CoreExport.h" #include "core/layout/ng/geometry/ng_static_position.h" +#include "core/layout/ng/ng_floating_object.h" #include "core/layout/ng/ng_physical_fragment.h" #include "platform/LayoutUnit.h" #include "platform/heap/Handle.h" @@ -15,7 +16,6 @@ namespace blink { class LayoutObject; -class NGPhysicalFragment; class NGBlockNode; struct NGFloatingObject; @@ -48,7 +48,7 @@ // The float cannot be positioned right away inside of the 1st div because // the vertical position is not known at that moment. It will be known only // after the 2nd div collapses its margin with its parent. - const Vector<Persistent<NGFloatingObject>>& UnpositionedFloats() const { + const Vector<RefPtr<NGFloatingObject>>& UnpositionedFloats() const { return unpositioned_floats_; } @@ -59,13 +59,13 @@ PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>& out_of_flow_descendants, Vector<NGStaticPosition> out_of_flow_positions, - Vector<Persistent<NGFloatingObject>>& unpositioned_floats); + Vector<RefPtr<NGFloatingObject>>& unpositioned_floats); RefPtr<NGPhysicalFragment> physical_fragment_; LayoutObject* layout_object_; PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_descendants_; Vector<NGStaticPosition> out_of_flow_positions_; - Vector<Persistent<NGFloatingObject>> unpositioned_floats_; + Vector<RefPtr<NGFloatingObject>> unpositioned_floats_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc index e3f359a..420b79fb 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
@@ -13,7 +13,7 @@ NGPhysicalSize size, NGPhysicalSize overflow, Vector<RefPtr<NGPhysicalFragment>>& children, - Vector<Persistent<NGFloatingObject>>& positioned_floats, + Vector<RefPtr<NGFloatingObject>>& positioned_floats, const WTF::Optional<NGLogicalOffset>& bfc_offset, const NGMarginStrut& end_margin_strut, RefPtr<NGBreakToken> break_token)
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h index f8031d47..c6c1542 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
@@ -8,8 +8,8 @@ #include "core/CoreExport.h" #include "core/layout/ng/geometry/ng_logical_offset.h" #include "core/layout/ng/geometry/ng_margin_strut.h" +#include "core/layout/ng/ng_floating_object.h" #include "core/layout/ng/ng_physical_fragment.h" -#include "platform/heap/Handle.h" #include "wtf/Optional.h" namespace blink { @@ -23,7 +23,7 @@ NGPhysicalSize size, NGPhysicalSize overflow, Vector<RefPtr<NGPhysicalFragment>>& children, - Vector<Persistent<NGFloatingObject>>& positioned_floats, + Vector<RefPtr<NGFloatingObject>>& positioned_floats, const WTF::Optional<NGLogicalOffset>& bfc_offset, const NGMarginStrut& end_margin_strut, RefPtr<NGBreakToken> break_token = nullptr); @@ -35,7 +35,7 @@ // List of positioned floats that need to be copied to the old layout tree. // TODO(layout-ng): remove this once we change painting code to handle floats // differently. - const Vector<Persistent<NGFloatingObject>>& PositionedFloats() const { + const Vector<RefPtr<NGFloatingObject>>& PositionedFloats() const { return positioned_floats_; } @@ -47,7 +47,7 @@ private: Vector<RefPtr<NGPhysicalFragment>> children_; - Vector<Persistent<NGFloatingObject>> positioned_floats_; + Vector<RefPtr<NGFloatingObject>> positioned_floats_; const WTF::Optional<NGLogicalOffset> bfc_offset_; const NGMarginStrut end_margin_strut_; };
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp index 9f1fb920..3985c762 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp
@@ -51,7 +51,7 @@ if (!layoutObject) return ClipStrategy::None; const ComputedStyle& style = layoutObject->styleRef(); - if (style.display() == EDisplay::None || + if (style.display() == EDisplay::kNone || style.visibility() != EVisibility::kVisible) return ClipStrategy::None; ClipStrategy strategy = ClipStrategy::None; @@ -71,7 +71,7 @@ if (isSVGUseElement(element)) { const LayoutObject* useLayoutObject = element.layoutObject(); if (!useLayoutObject || - useLayoutObject->styleRef().display() == EDisplay::None) + useLayoutObject->styleRef().display() == EDisplay::kNone) return ClipStrategy::None; const SVGGraphicsElement* shapeElement = toSVGUseElement(element).visibleTargetGraphicsElementForClipping();
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp index e215ce3..7d1df37 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp
@@ -88,7 +88,7 @@ for (const SVGElement& childElement : Traversal<SVGElement>::childrenOf(*element())) { const LayoutObject* layoutObject = childElement.layoutObject(); - if (!layoutObject || layoutObject->styleRef().display() == EDisplay::None) + if (!layoutObject || layoutObject->styleRef().display() == EDisplay::kNone) continue; SVGPaintContext::paintResourceSubtree(builder.context(), layoutObject); } @@ -101,7 +101,7 @@ for (const SVGElement& childElement : Traversal<SVGElement>::childrenOf(*element())) { const LayoutObject* layoutObject = childElement.layoutObject(); - if (!layoutObject || layoutObject->styleRef().display() == EDisplay::None) + if (!layoutObject || layoutObject->styleRef().display() == EDisplay::kNone) continue; m_maskContentBoundaries.unite( layoutObject->localToSVGParentTransform().mapRect(
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp index e3d0528a..01d958f 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -230,8 +230,8 @@ LayoutRect LayoutSVGRoot::overflowClipRect(const LayoutPoint& location, OverlayScrollbarClipBehavior) const { - return LayoutRect(pixelSnappedIntRect( - LayoutReplaced::overflowClipRect(location, IgnoreOverlayScrollbarSize))); + return LayoutRect(pixelSnappedIntRect(LayoutReplaced::overflowClipRect( + location, IgnorePlatformOverlayScrollbarSize))); } void LayoutSVGRoot::paintReplaced(const PaintInfo& paintInfo,
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h index d9bc63b..a410c11 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
@@ -90,7 +90,8 @@ LayoutRect visualOverflowRect() const override; LayoutRect overflowClipRect( const LayoutPoint& location, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; bool hasNonIsolatedBlendingDescendants() const final;
diff --git a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp index f178e994..51d4b2a 100644 --- a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp +++ b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
@@ -20,6 +20,7 @@ callback->call(wrappable, result); } +// static MojoWatcher* MojoWatcher::create(mojo::Handle handle, const MojoHandleSignals& signalsDict, MojoWatchCallback* callback, @@ -42,42 +43,16 @@ return watcher; } -MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) - : ContextLifecycleObserver(context), - m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), - m_callback(this, callback) {} - MojoWatcher::~MojoWatcher() { DCHECK(!m_handle.is_valid()); } -MojoResult MojoWatcher::watch(mojo::Handle handle, - const MojoHandleSignals& signalsDict) { - ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; - if (signalsDict.readable()) - signals |= MOJO_HANDLE_SIGNAL_READABLE; - if (signalsDict.writable()) - signals |= MOJO_HANDLE_SIGNAL_WRITABLE; - if (signalsDict.peerClosed()) - signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; - - MojoResult result = - MojoWatch(handle.value(), signals, &MojoWatcher::onHandleReady, - reinterpret_cast<uintptr_t>(this)); - if (result == MOJO_RESULT_OK) { - m_handle = handle; - } - return result; -} - MojoResult MojoWatcher::cancel() { - if (!m_handle.is_valid()) - return MOJO_RESULT_OK; + if (!m_watcherHandle.is_valid()) + return MOJO_RESULT_INVALID_ARGUMENT; - MojoResult result = - MojoCancelWatch(m_handle.value(), reinterpret_cast<uintptr_t>(this)); - m_handle = mojo::Handle(); - return result; + m_watcherHandle.reset(); + return MOJO_RESULT_OK; } DEFINE_TRACE(MojoWatcher) { @@ -97,13 +72,76 @@ cancel(); } +MojoWatcher::MojoWatcher(ExecutionContext* context, MojoWatchCallback* callback) + : ContextLifecycleObserver(context), + m_taskRunner(TaskRunnerHelper::get(TaskType::UnspecedTimer, context)), + m_callback(this, callback) {} + +MojoResult MojoWatcher::watch(mojo::Handle handle, + const MojoHandleSignals& signalsDict) { + ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE; + if (signalsDict.readable()) + signals |= MOJO_HANDLE_SIGNAL_READABLE; + if (signalsDict.writable()) + signals |= MOJO_HANDLE_SIGNAL_WRITABLE; + if (signalsDict.peerClosed()) + signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + + MojoResult result = + mojo::CreateWatcher(&MojoWatcher::onHandleReady, &m_watcherHandle); + DCHECK_EQ(MOJO_RESULT_OK, result); + + result = MojoWatch(m_watcherHandle.get().value(), handle.value(), signals, + reinterpret_cast<uintptr_t>(this)); + if (result != MOJO_RESULT_OK) + return result; + + m_handle = handle; + + MojoResult readyResult; + result = arm(&readyResult); + if (result == MOJO_RESULT_OK) + return result; + + // We couldn't arm the watcher because the handle is already ready to + // trigger a success notification. Post a notification manually. + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + m_taskRunner->postTask(BLINK_FROM_HERE, + WTF::bind(&MojoWatcher::runReadyCallback, + wrapPersistent(this), readyResult)); + return MOJO_RESULT_OK; +} + +MojoResult MojoWatcher::arm(MojoResult* readyResult) { + // Nothing to do if the watcher is inactive. + if (!m_handle.is_valid()) + return MOJO_RESULT_OK; + + uint32_t numReadyContexts = 1; + uintptr_t readyContext; + MojoResult localReadyResult; + MojoHandleSignalsState readySignals; + MojoResult result = + MojoArmWatcher(m_watcherHandle.get().value(), &numReadyContexts, + &readyContext, &localReadyResult, &readySignals); + if (result == MOJO_RESULT_OK) + return MOJO_RESULT_OK; + + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + DCHECK_EQ(1u, numReadyContexts); + DCHECK_EQ(reinterpret_cast<uintptr_t>(this), readyContext); + *readyResult = localReadyResult; + return result; +} + void MojoWatcher::onHandleReady(uintptr_t context, MojoResult result, MojoHandleSignalsState, - MojoWatchNotificationFlags) { - // It is safe to assume the MojoWatcher still exists because this - // callback will never be run after MojoWatcher destructor, - // which cancels the watch. + MojoWatcherNotificationFlags) { + // It is safe to assume the MojoWatcher still exists. It stays alive at least + // as long as |m_handle| is valid, and |m_handle| is only reset after we + // dispatch a |MOJO_RESULT_CANCELLED| notification. That is always the last + // notification received by this callback. MojoWatcher* watcher = reinterpret_cast<MojoWatcher*>(context); watcher->m_taskRunner->postTask( BLINK_FROM_HERE, @@ -112,17 +150,41 @@ } void MojoWatcher::runReadyCallback(MojoResult result) { - // Ignore callbacks if not watching. - if (!m_handle.is_valid()) - return; - - // MOJO_RESULT_CANCELLED indicates that the handle has been closed, in which - // case watch has been implicitly cancelled. There is no need to explicitly - // cancel the watch. - if (result == MOJO_RESULT_CANCELLED) + if (result == MOJO_RESULT_CANCELLED) { + // Last notification. m_handle = mojo::Handle(); + // Only dispatch to the callback if this cancellation was implicit due to + // |m_handle| closure. If it was explicit, |m_watcherHandle| has already + // been reset. + if (m_watcherHandle.is_valid()) { + m_watcherHandle.reset(); + runWatchCallback(m_callback, this, result); + } + return; + } + + // Ignore callbacks if not watching. + if (!m_watcherHandle.is_valid()) + return; + runWatchCallback(m_callback, this, result); + + // Rearm the watcher so another notification can fire. + // + // TODO(rockot): MojoWatcher should expose some better approximation of the + // new watcher API, including explicit add and removal of handles from the + // watcher, as well as explicit arming. + MojoResult readyResult; + MojoResult armResult = arm(&readyResult); + if (armResult == MOJO_RESULT_OK) + return; + + DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, armResult); + + m_taskRunner->postTask(BLINK_FROM_HERE, + WTF::bind(&MojoWatcher::runReadyCallback, + wrapWeakPersistent(this), readyResult)); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/mojo/MojoWatcher.h b/third_party/WebKit/Source/core/mojo/MojoWatcher.h index fe6e193..99671de8 100644 --- a/third_party/WebKit/Source/core/mojo/MojoWatcher.h +++ b/third_party/WebKit/Source/core/mojo/MojoWatcher.h
@@ -10,6 +10,7 @@ #include "bindings/core/v8/TraceWrapperMember.h" #include "core/dom/ContextLifecycleObserver.h" #include "mojo/public/cpp/system/handle.h" +#include "mojo/public/cpp/system/watcher.h" namespace blink { @@ -47,15 +48,17 @@ MojoWatcher(ExecutionContext*, MojoWatchCallback*); MojoResult watch(mojo::Handle, const MojoHandleSignals&); + MojoResult arm(MojoResult* readyResult); static void onHandleReady(uintptr_t context, MojoResult, MojoHandleSignalsState, - MojoWatchNotificationFlags); + MojoWatcherNotificationFlags); void runReadyCallback(MojoResult); RefPtr<WebTaskRunner> m_taskRunner; TraceWrapperMember<MojoWatchCallback> m_callback; + mojo::ScopedWatcherHandle m_watcherHandle; mojo::Handle m_handle; };
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp index c270afe..257a0c5 100644 --- a/third_party/WebKit/Source/core/page/Page.cpp +++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -128,6 +128,7 @@ m_deviceScaleFactor(1), m_visibilityState(PageVisibilityStateVisible), m_isCursorVisible(true), + m_subframeCount(0), m_frameHost(FrameHost::create(*this)) { ASSERT(m_editorClient); @@ -424,6 +425,25 @@ return m_isCursorVisible; } +#if DCHECK_IS_ON() +void checkFrameCountConsistency(int expectedFrameCount, Frame* frame) { + DCHECK_GE(expectedFrameCount, 0); + + int actualFrameCount = 0; + for (; frame; frame = frame->tree().traverseNext()) + ++actualFrameCount; + + DCHECK_EQ(expectedFrameCount, actualFrameCount); +} +#endif + +int Page::subframeCount() const { +#if DCHECK_IS_ON() + checkFrameCountConsistency(m_subframeCount + 1, mainFrame()); +#endif + return m_subframeCount; +} + void Page::settingsChanged(SettingsDelegate::ChangeType changeType) { switch (changeType) { case SettingsDelegate::StyleChange: @@ -555,7 +575,7 @@ // TODO(rbyers): Most of this doesn't appear to take into account that each // SVGImage gets it's own Page instance. - frameHost().consoleMessageStorage().clear(); + consoleMessageStorage().clear(); useCounter().didCommitLoad(url); deprecation().clearSuppression(); visualViewport().sendUMAMetrics();
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h index d427c88..25f9144 100644 --- a/third_party/WebKit/Source/core/page/Page.h +++ b/third_party/WebKit/Source/core/page/Page.h
@@ -250,6 +250,18 @@ bool isCursorVisible() const; void setIsCursorVisible(bool isVisible) { m_isCursorVisible = isVisible; } + // Don't allow more than a certain number of frames in a page. + // This seems like a reasonable upper bound, and otherwise mutually + // recursive frameset pages can quickly bring the program to its knees + // with exponential growth in the number of frames. + static const int maxNumberOfFrames = 1000; + void incrementSubframeCount() { ++m_subframeCount; } + void decrementSubframeCount() { + DCHECK_GT(m_subframeCount, 0); + --m_subframeCount; + } + int subframeCount() const; + void setDefaultPageScaleLimits(float minScale, float maxScale); void setUserAgentPageScaleConstraints( const PageScaleConstraints& newConstraints); @@ -346,6 +358,8 @@ bool m_isPainting = false; #endif + int m_subframeCount; + // A pointer to all the interfaces provided to in-process Frames for this // Page. // FIXME: Most of the members of Page should move onto FrameHost.
diff --git a/third_party/WebKit/Source/core/paint/ClipRectsCache.h b/third_party/WebKit/Source/core/paint/ClipRectsCache.h index 0fb9aae..3b54ee9 100644 --- a/third_party/WebKit/Source/core/paint/ClipRectsCache.h +++ b/third_party/WebKit/Source/core/paint/ClipRectsCache.h
@@ -41,7 +41,7 @@ : root(nullptr) #if DCHECK_IS_ON() , - overlayScrollbarClipBehavior(IgnoreOverlayScrollbarSize) + overlayScrollbarClipBehavior(IgnorePlatformOverlayScrollbarSize) #endif { }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h index ad43b9f..a79763d 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.h +++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -845,7 +845,7 @@ const LayoutRect& dirtyRect, ClipRectsCacheSlot, GeometryMapperOption, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize, + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize, ShouldRespectOverflowClipType = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutSize& subPixelAccumulation = LayoutSize()); @@ -855,7 +855,7 @@ const LayoutRect& dirtyRect, ClipRectsCacheSlot, GeometryMapperOption, - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize, + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize, ShouldRespectOverflowClipType = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutSize& subPixelAccumulation = LayoutSize(),
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp index ec07bc0..e7dbd747 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -588,7 +588,8 @@ const LayoutSize& subpixelAccumulation) const { DCHECK(!m_geometryMapper); ClipRectsContext context(rootLayer, PaintingClipRects, - IgnoreOverlayScrollbarSize, subpixelAccumulation); + IgnorePlatformOverlayScrollbarSize, + subpixelAccumulation); if (respectOverflowClip == IgnoreOverflowClip) context.setIgnoreOverflowClip(); return getClipRects(context);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h index 61d860f..a98c1fe 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
@@ -66,7 +66,7 @@ ClipRectsContext(const PaintLayer* root, ClipRectsCacheSlot slot, OverlayScrollbarClipBehavior overlayScrollbarClipBehavior = - IgnoreOverlayScrollbarSize, + IgnorePlatformOverlayScrollbarSize, const LayoutSize& accumulation = LayoutSize()) : rootLayer(root), overlayScrollbarClipBehavior(overlayScrollbarClipBehavior),
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp index 8645e8bc..19ae3988e 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
@@ -48,7 +48,7 @@ PaintLayer* targetPaintLayer = toLayoutBoxModelObject(target->layoutObject())->layer(); ClipRectsContext context(document().layoutView()->layer(), UncachedClipRects, - IgnoreOverlayScrollbarSize, + IgnorePlatformOverlayScrollbarSize, LayoutSize(FloatSize(0.25, 0.35))); // When RLS is enabled, the LayoutView will have a composited scrolling layer, // so don't apply an overflow clip.
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp index 9fc2b4d..aa63b15 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -450,23 +450,23 @@ paintLayerForFragments->appendSingleFragmentIgnoringPagination( layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, geometryMapperOption, - IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, - localPaintingInfo.subPixelAccumulation); + IgnorePlatformOverlayScrollbarSize, respectOverflowClip, + &offsetFromRoot, localPaintingInfo.subPixelAccumulation); } else if (isFixedPositionObjectInPagedMedia()) { PaintLayerFragments singleFragment; paintLayerForFragments->appendSingleFragmentIgnoringPagination( singleFragment, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, geometryMapperOption, - IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, - localPaintingInfo.subPixelAccumulation); + IgnorePlatformOverlayScrollbarSize, respectOverflowClip, + &offsetFromRoot, localPaintingInfo.subPixelAccumulation); repeatFixedPositionObjectInPages(singleFragment[0], paintingInfo, layerFragments); } else { paintLayerForFragments->collectFragments( layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, geometryMapperOption, - IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, - localPaintingInfo.subPixelAccumulation); + IgnorePlatformOverlayScrollbarSize, respectOverflowClip, + &offsetFromRoot, localPaintingInfo.subPixelAccumulation); } if (paintFlags & PaintLayerPaintingAncestorClippingMaskPhase) { @@ -729,7 +729,7 @@ // here. paginationLayer->collectFragments( layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, - cacheSlot, geometryMapperOption, IgnoreOverlayScrollbarSize, + cacheSlot, geometryMapperOption, IgnorePlatformOverlayScrollbarSize, respectOverflowClip, nullptr, paintingInfo.subPixelAccumulation, &transformedExtent); } @@ -746,7 +746,7 @@ paintingInfo.rootLayer, (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, - IgnoreOverlayScrollbarSize); + IgnorePlatformOverlayScrollbarSize); if (shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()) == IgnoreOverflowClip) clipRectsContext.setIgnoreOverflowClip();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index 291ea69..0ffab47 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -506,7 +506,10 @@ IntSize contentSize = contentsSize(); IntSize visibleSize = - pixelSnappedIntRect(box().overflowClipRect(box().location())).size(); + pixelSnappedIntRect( + box().overflowClipRect(box().location(), + IgnorePlatformAndCSSOverlayScrollbarSize)) + .size(); Page* page = layoutBox()->document().page(); DCHECK(page); @@ -1300,10 +1303,16 @@ OverlayScrollbarClipBehavior overlayScrollbarClipBehavior) const { if (!hasVerticalScrollbar()) return 0; - if ((verticalScrollbar()->isOverlayScrollbar() || - box().style()->overflowY() == EOverflow::kOverlay) && - (overlayScrollbarClipBehavior == IgnoreOverlayScrollbarSize || - !verticalScrollbar()->shouldParticipateInHitTesting())) { + if (overlayScrollbarClipBehavior == + IgnorePlatformAndCSSOverlayScrollbarSize && + box().style()->overflowY() == EOverflow::kOverlay) { + return 0; + } + if ((overlayScrollbarClipBehavior == IgnorePlatformOverlayScrollbarSize || + overlayScrollbarClipBehavior == + IgnorePlatformAndCSSOverlayScrollbarSize || + !verticalScrollbar()->shouldParticipateInHitTesting()) && + verticalScrollbar()->isOverlayScrollbar()) { return 0; } return verticalScrollbar()->scrollbarThickness(); @@ -1313,10 +1322,16 @@ OverlayScrollbarClipBehavior overlayScrollbarClipBehavior) const { if (!hasHorizontalScrollbar()) return 0; - if ((horizontalScrollbar()->isOverlayScrollbar() || - box().style()->overflowX() == EOverflow::kOverlay) && - (overlayScrollbarClipBehavior == IgnoreOverlayScrollbarSize || - !horizontalScrollbar()->shouldParticipateInHitTesting())) { + if (overlayScrollbarClipBehavior == + IgnorePlatformAndCSSOverlayScrollbarSize && + box().style()->overflowX() == EOverflow::kOverlay) { + return 0; + } + if ((overlayScrollbarClipBehavior == IgnorePlatformOverlayScrollbarSize || + overlayScrollbarClipBehavior == + IgnorePlatformAndCSSOverlayScrollbarSize || + !horizontalScrollbar()->shouldParticipateInHitTesting()) && + horizontalScrollbar()->isOverlayScrollbar()) { return 0; } return horizontalScrollbar()->scrollbarThickness();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h index e444af6..af36380 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -356,9 +356,11 @@ int pixelSnappedScrollHeight() const; int verticalScrollbarWidth( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; int horizontalScrollbarHeight( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const override; + OverlayScrollbarClipBehavior = + IgnorePlatformOverlayScrollbarSize) const override; DoubleSize adjustedScrollOffset() const { return toDoubleSize(DoublePoint(scrollOrigin()) + m_scrollOffset);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp index a7758783d..24a7855 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
@@ -722,4 +722,21 @@ EXPECT_EQ(FloatSize(60, 60), overflowClip->clipRect().rect().size()); } +TEST_P(PaintPropertyTreeUpdateTest, Preserve3DChange) { + setBodyInnerHTML( + "<div id='parent'>" + " <div id='child' style='transform: translate3D(1px, 2px, 3px)'></div>" + "</div>"); + + auto* child = getLayoutObjectByElementId("child"); + auto* transform = child->paintProperties()->transform(); + EXPECT_TRUE(transform->flattensInheritedTransform()); + + document().getElementById("parent")->setAttribute( + HTMLNames::styleAttr, "transform-style: preserve-3d"); + document().view()->updateAllLifecyclePhases(); + EXPECT_EQ(transform, child->paintProperties()->transform()); + EXPECT_FALSE(transform->flattensInheritedTransform()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index 204d91b..218cdd8 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -830,7 +830,7 @@ (borderRightStyle() == BorderStyleNone && other.borderRightStyle() == BorderStyleHidden))) return true; - } else if (display() == EDisplay::ListItem) { + } else if (display() == EDisplay::kListItem) { if (listStyleType() != other.listStyleType() || listStylePosition() != other.listStylePosition()) return true;
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index aedafd4..2dfd875 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -851,7 +851,7 @@ void setContent(ContentData*); // display - static EDisplay initialDisplay() { return EDisplay::Inline; } + static EDisplay initialDisplay() { return EDisplay::kInline; } EDisplay display() const { return static_cast<EDisplay>(m_nonInheritedData.m_effectiveDisplay); } @@ -3570,39 +3570,42 @@ } static bool isDisplayBlockContainer(EDisplay display) { - return display == EDisplay::Block || display == EDisplay::ListItem || - display == EDisplay::InlineBlock || display == EDisplay::FlowRoot || - display == EDisplay::TableCell || display == EDisplay::TableCaption; + return display == EDisplay::kBlock || display == EDisplay::kListItem || + display == EDisplay::kInlineBlock || + display == EDisplay::kFlowRoot || display == EDisplay::kTableCell || + display == EDisplay::kTableCaption; } static bool isDisplayFlexibleBox(EDisplay display) { - return display == EDisplay::Flex || display == EDisplay::InlineFlex; + return display == EDisplay::kFlex || display == EDisplay::kInlineFlex; } static bool isDisplayGridBox(EDisplay display) { - return display == EDisplay::Grid || display == EDisplay::InlineGrid; + return display == EDisplay::kGrid || display == EDisplay::kInlineGrid; } static bool isDisplayReplacedType(EDisplay display) { - return display == EDisplay::InlineBlock || - display == EDisplay::WebkitInlineBox || - display == EDisplay::InlineFlex || - display == EDisplay::InlineTable || display == EDisplay::InlineGrid; + return display == EDisplay::kInlineBlock || + display == EDisplay::kWebkitInlineBox || + display == EDisplay::kInlineFlex || + display == EDisplay::kInlineTable || + display == EDisplay::kInlineGrid; } static bool isDisplayInlineType(EDisplay display) { - return display == EDisplay::Inline || isDisplayReplacedType(display); + return display == EDisplay::kInline || isDisplayReplacedType(display); } static bool isDisplayTableType(EDisplay display) { - return display == EDisplay::Table || display == EDisplay::InlineTable || - display == EDisplay::TableRowGroup || - display == EDisplay::TableHeaderGroup || - display == EDisplay::TableFooterGroup || - display == EDisplay::TableRow || - display == EDisplay::TableColumnGroup || - display == EDisplay::TableColumn || display == EDisplay::TableCell || - display == EDisplay::TableCaption; + return display == EDisplay::kTable || display == EDisplay::kInlineTable || + display == EDisplay::kTableRowGroup || + display == EDisplay::kTableHeaderGroup || + display == EDisplay::kTableFooterGroup || + display == EDisplay::kTableRow || + display == EDisplay::kTableColumnGroup || + display == EDisplay::kTableColumn || + display == EDisplay::kTableCell || + display == EDisplay::kTableCaption; } // Color accessors are all private to make sure callers use
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h index 1175eed8..e16a15c 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h +++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -335,29 +335,29 @@ }; enum class EDisplay : unsigned { - Inline, - Block, - ListItem, - InlineBlock, - Table, - InlineTable, - TableRowGroup, - TableHeaderGroup, - TableFooterGroup, - TableRow, - TableColumnGroup, - TableColumn, - TableCell, - TableCaption, - WebkitBox, - WebkitInlineBox, - Flex, - InlineFlex, - Grid, - InlineGrid, - Contents, - FlowRoot, - None + kInline, + kBlock, + kListItem, + kInlineBlock, + kTable, + kInlineTable, + kTableRowGroup, + kTableHeaderGroup, + kTableFooterGroup, + kTableRow, + kTableColumnGroup, + kTableColumn, + kTableCell, + kTableCaption, + kWebkitBox, + kWebkitInlineBox, + kFlex, + kInlineFlex, + kGrid, + kInlineGrid, + kContents, + kFlowRoot, + kNone }; enum class EInsideLink : unsigned {
diff --git a/third_party/WebKit/Source/core/svg/SVGGElement.cpp b/third_party/WebKit/Source/core/svg/SVGGElement.cpp index 1d5541a..bf029b04c 100644 --- a/third_party/WebKit/Source/core/svg/SVGGElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGGElement.cpp
@@ -38,7 +38,7 @@ // We still have to create layoutObjects for the <g> & <linearGradient> // element, though the subtree may be hidden - we only want the resource // layoutObjects to exist so they can be referenced from somewhere else. - if (style.display() == EDisplay::None) + if (style.display() == EDisplay::kNone) return new LayoutSVGHiddenContainer(this); return new LayoutSVGTransformableContainer(this);
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js index 32107ca..e1c8f01 100644 --- a/third_party/WebKit/Source/devtools/front_end/Tests.js +++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -514,22 +514,19 @@ TestSuite.prototype.testConsoleOnNavigateBack = function() { function filteredMessages() { - return SDK.multitargetConsoleModel.messages().filter( - a => a.source !== SDK.ConsoleMessage.MessageSource.Violation); + return SDK.consoleModel.messages().filter(a => a.source !== SDK.ConsoleMessage.MessageSource.Violation); } - if (filteredMessages().length === 1) { + if (filteredMessages().length === 1) firstConsoleMessageReceived.call(this, null); - } else { - SDK.multitargetConsoleModel.addEventListener( - SDK.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this); - } + else + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this); + function firstConsoleMessageReceived(event) { if (event && event.data.source === SDK.ConsoleMessage.MessageSource.Violation) return; - SDK.multitargetConsoleModel.removeEventListener( - SDK.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this); + SDK.consoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, firstConsoleMessageReceived, this); this.evaluateInConsole_('clickLink();', didClickLink.bind(this)); } @@ -685,12 +682,12 @@ messages.splice(index, 1); if (!messages.length) { - SDK.multitargetConsoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); + SDK.consoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); next(); } } - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); SDK.multitargetNetworkManager.setNetworkConditions(preset); } @@ -835,7 +832,7 @@ }; TestSuite.prototype.testWindowInitializedOnNavigateBack = function() { - var messages = SDK.multitargetConsoleModel.messages(); + var messages = SDK.consoleModel.messages(); this.assertEquals(1, messages.length); var text = messages[0].messageText; if (text.indexOf('Uncaught') !== -1) @@ -870,7 +867,7 @@ }; TestSuite.prototype.waitForTestResultsInConsole = function() { - var messages = SDK.multitargetConsoleModel.messages(); + var messages = SDK.consoleModel.messages(); for (var i = 0; i < messages.length; ++i) { var text = messages[i].messageText; if (text === 'PASS') @@ -887,7 +884,7 @@ this.fail(text); } - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage, this); this.takeControl(); }; @@ -931,12 +928,12 @@ Array.prototype.slice.call(arguments, 1, -1).map(arg => JSON.stringify(arg)).join(',') + ','; this.evaluateInConsole_( `${functionName}(${argsString} function() { console.log('${doneMessage}'); });`, function() {}); - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage); function onConsoleMessage(event) { var text = event.data.messageText; if (text === doneMessage) { - SDK.multitargetConsoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage); + SDK.consoleModel.removeEventListener(SDK.ConsoleModel.Events.MessageAdded, onConsoleMessage); callback(); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/PresentationConsoleMessageHelper.js b/third_party/WebKit/Source/devtools/front_end/bindings/PresentationConsoleMessageHelper.js index 591ba99..cb1e587 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/PresentationConsoleMessageHelper.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/PresentationConsoleMessageHelper.js
@@ -44,10 +44,9 @@ /** @type {!Array.<!Bindings.PresentationConsoleMessage>} */ this._presentationConsoleMessages = []; - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); - SDK.multitargetConsoleModel.addEventListener( - SDK.ConsoleModel.Events.MessageAdded, this._onConsoleMessageAdded, this); - SDK.multitargetConsoleModel.messages().forEach(this._consoleMessageAdded, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, this._onConsoleMessageAdded, this); + SDK.consoleModel.messages().forEach(this._consoleMessageAdded, this); // TODO(dgozman): setImmediate because we race with DebuggerWorkspaceBinding on ParsedScriptSource event delivery. SDK.targetManager.addModelListener( SDK.DebuggerModel, SDK.DebuggerModel.Events.ParsedScriptSource,
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js index caa0df9..0704bbc 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsolePrompt.js
@@ -191,7 +191,7 @@ this.setText(''); var currentExecutionContext = UI.context.flavor(SDK.ExecutionContext); if (currentExecutionContext) { - SDK.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, text, useCommandLineAPI); + SDK.consoleModel.evaluateCommandInConsole(currentExecutionContext, text, useCommandLineAPI); if (Console.ConsolePanel.instance().isShowing()) Host.userMetrics.actionTaken(Host.UserMetrics.Action.CommandEvaluatedInConsolePanel); }
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js index 3ca49b0..12af176 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -182,8 +182,7 @@ } static clearConsole() { - for (var target of SDK.targetManager.targets()) - target.consoleModel.requestClearMessages(); + SDK.consoleModel.requestClearMessages(); } /** @@ -226,14 +225,11 @@ } _fetchMultitargetMessages() { - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); - SDK.multitargetConsoleModel.addEventListener( - SDK.ConsoleModel.Events.MessageAdded, this._onConsoleMessageAdded, this); - SDK.multitargetConsoleModel.addEventListener( - SDK.ConsoleModel.Events.MessageUpdated, this._onConsoleMessageUpdated, this); - SDK.multitargetConsoleModel.addEventListener( - SDK.ConsoleModel.Events.CommandEvaluated, this._commandEvaluated, this); - SDK.multitargetConsoleModel.messages().forEach(this._addConsoleMessage, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, this._onConsoleMessageAdded, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageUpdated, this._onConsoleMessageUpdated, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.CommandEvaluated, this._commandEvaluated, this); + SDK.consoleModel.messages().forEach(this._addConsoleMessage, this); this._viewport.invalidate(); } @@ -806,7 +802,7 @@ result.target(), exceptionDetails, SDK.ConsoleMessage.MessageType.Result, undefined, undefined); } message.setOriginatingMessage(originatingConsoleMessage); - result.target().consoleModel.addMessage(message); + SDK.consoleModel.addMessage(message); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index 10ca4c15..bfa3748 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -165,7 +165,7 @@ UI.ContextMenu.installHandler(document); UI.Tooltip.installHandler(document); Components.dockController = new Components.DockController(canDock); - SDK.multitargetConsoleModel = new SDK.MultitargetConsoleModel(); + SDK.consoleModel = new SDK.ConsoleModel(); SDK.multitargetNetworkManager = new SDK.MultitargetNetworkManager(); SDK.targetManager.addEventListener( SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this)); @@ -602,9 +602,9 @@ this._warnings = this._createItem(shadowRoot, 'smallicon-warning'); this._titles = []; - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._update, this); - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, this._update, this); - SDK.multitargetConsoleModel.addEventListener(SDK.ConsoleModel.Events.MessageUpdated, this._update, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._update, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageAdded, this._update, this); + SDK.consoleModel.addEventListener(SDK.ConsoleModel.Events.MessageUpdated, this._update, this); this._update(); } @@ -637,13 +637,8 @@ } _update() { - var errors = 0; - var warnings = 0; - var targets = SDK.targetManager.targets(); - for (var i = 0; i < targets.length; ++i) { - errors += targets[i].consoleModel.errors(); - warnings += targets[i].consoleModel.warnings(); - } + var errors = SDK.consoleModel.errors(); + var warnings = SDK.consoleModel.warnings(); this._titles = []; this._toolbarItem.setVisible(!!(errors || warnings));
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js index 960b93b..2001eb2 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
@@ -86,7 +86,7 @@ columnConfig.titleDOMFragment = this._makeHeaderFragment(columnConfig.title, columnConfig.subtitle); this._columns.push(columnConfig); } - this._loadColumns(); + this._loadCustomColumnsAndSettings(); this._popoverHelper = new UI.PopoverHelper(this._networkLogView.element); this._popoverHelper.initializeCallbacks( @@ -330,13 +330,13 @@ * @param {!Network.NetworkLogViewColumns.Descriptor} columnConfig */ _toggleColumnVisibility(columnConfig) { - this._loadColumns(); + this._loadCustomColumnsAndSettings(); columnConfig.visible = !columnConfig.visible; - this._saveColumns(); + this._saveColumnsSettings(); this._updateColumns(); } - _saveColumns() { + _saveColumnsSettings() { var saveableSettings = {}; for (var columnConfig of this._columns) saveableSettings[columnConfig.id] = {visible: columnConfig.visible, title: columnConfig.title}; @@ -344,7 +344,7 @@ this._persistantSettings.set(saveableSettings); } - _loadColumns() { + _loadCustomColumnsAndSettings() { var savedSettings = this._persistantSettings.get(); var columnIds = Object.keys(savedSettings); for (var columnId of columnIds) { @@ -461,7 +461,7 @@ return false; this._columns.splice(index, 1); this._dataGrid.removeColumn(headerId); - this._saveColumns(); + this._saveColumnsSettings(); this._updateColumns(); return true; } @@ -494,7 +494,7 @@ this._columns.splice(index, 0, columnConfig); if (this._dataGrid) this._dataGrid.addColumn(Network.NetworkLogViewColumns._convertToDataGridDescriptor(columnConfig), index); - this._saveColumns(); + this._saveColumnsSettings(); this._updateColumns(); return columnConfig; }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js index 167cb26..f9e5681 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js
@@ -29,52 +29,76 @@ */ /** - * @unrestricted + * @implements {SDK.TargetManager.Observer} */ -SDK.ConsoleModel = class extends SDK.SDKModel { - /** - * @param {!SDK.Target} target - */ - constructor(target) { - super(target); +SDK.ConsoleModel = class extends Common.Object { + constructor() { + super(); /** @type {!Array.<!SDK.ConsoleMessage>} */ this._messages = []; - /** @type {!Map<number, !SDK.ConsoleMessage>} */ + /** @type {!Map<!SDK.Target, !Map<number, !SDK.ConsoleMessage>>} */ this._messageByExceptionId = new Map(); this._warnings = 0; this._errors = 0; + SDK.targetManager.observeTargets(this); + } + + /** + * @override + * @param {!SDK.Target} target + */ + targetAdded(target) { + var eventListeners = []; + var logModel = target.model(SDK.LogModel); if (logModel) - logModel.on(SDK.LogModel.EntryAddedEvent, this._logEntryAdded, this); + eventListeners.push(logModel.on(SDK.LogModel.EntryAddedEvent, this._logEntryAdded, this)); var cpuProfilerModel = target.model(SDK.CPUProfilerModel); if (cpuProfilerModel) { - cpuProfilerModel.addEventListener( - SDK.CPUProfilerModel.Events.ConsoleProfileStarted, this._consoleProfileStarted, this); - cpuProfilerModel.addEventListener( - SDK.CPUProfilerModel.Events.ConsoleProfileFinished, this._consoleProfileFinished, this); + eventListeners.push(cpuProfilerModel.addEventListener( + SDK.CPUProfilerModel.Events.ConsoleProfileStarted, this._consoleProfileStarted.bind(this, cpuProfilerModel))); + eventListeners.push(cpuProfilerModel.addEventListener( + SDK.CPUProfilerModel.Events.ConsoleProfileFinished, + this._consoleProfileFinished.bind(this, cpuProfilerModel))); } var resourceTreeModel = target.model(SDK.ResourceTreeModel); if (resourceTreeModel) { - resourceTreeModel.addEventListener( - SDK.ResourceTreeModel.Events.MainFrameStartedLoading, this._mainFrameStartedLoading, this); - resourceTreeModel.addEventListener( - SDK.ResourceTreeModel.Events.MainFrameNavigated, this._mainFrameNavigated, this); + eventListeners.push(resourceTreeModel.addEventListener( + SDK.ResourceTreeModel.Events.MainFrameStartedLoading, this._mainFrameStartedLoading, this)); + eventListeners.push(resourceTreeModel.addEventListener( + SDK.ResourceTreeModel.Events.MainFrameNavigated, this._mainFrameNavigated, this)); } var runtimeModel = target.model(SDK.RuntimeModel); if (runtimeModel) { - runtimeModel.addEventListener(SDK.RuntimeModel.Events.ExceptionThrown, this._exceptionThrown, this); - runtimeModel.addEventListener(SDK.RuntimeModel.Events.ExceptionRevoked, this._exceptionRevoked, this); - runtimeModel.addEventListener(SDK.RuntimeModel.Events.ConsoleAPICalled, this._consoleAPICalled, this); + eventListeners.push(runtimeModel.addEventListener( + SDK.RuntimeModel.Events.ExceptionThrown, this._exceptionThrown.bind(this, runtimeModel))); + eventListeners.push(runtimeModel.addEventListener( + SDK.RuntimeModel.Events.ExceptionRevoked, this._exceptionRevoked.bind(this, runtimeModel))); + eventListeners.push(runtimeModel.addEventListener( + SDK.RuntimeModel.Events.ConsoleAPICalled, this._consoleAPICalled.bind(this, runtimeModel))); } var networkManager = target.model(SDK.NetworkManager); - if (networkManager) - networkManager.addEventListener(SDK.NetworkManager.Events.WarningGenerated, this._networkWarningGenerated, this); + if (networkManager) { + eventListeners.push(networkManager.addEventListener( + SDK.NetworkManager.Events.WarningGenerated, this._networkWarningGenerated.bind(this, networkManager))); + } + + target[SDK.ConsoleModel._events] = eventListeners; + } + + /** + * @override + * @param {!SDK.Target} target + */ + targetRemoved(target) { + this._messageByExceptionId.delete(target); + Common.EventTarget.removeEventListeners(target[SDK.ConsoleModel._events]); } /** @@ -82,29 +106,29 @@ * @param {string} text * @param {boolean} useCommandLineAPI */ - static evaluateCommandInConsole(executionContext, text, useCommandLineAPI) { + evaluateCommandInConsole(executionContext, text, useCommandLineAPI) { var target = executionContext.target(); var requestedText = text; var commandMessage = new SDK.ConsoleMessage( target, SDK.ConsoleMessage.MessageSource.JS, null, text, SDK.ConsoleMessage.MessageType.Command); commandMessage.setExecutionContextId(executionContext.id); - target.consoleModel.addMessage(commandMessage); + this.addMessage(commandMessage); /** * @param {?SDK.RemoteObject} result * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails + * @this {SDK.ConsoleModel} */ function printResult(result, exceptionDetails) { if (!result) return; - Common.console.showPromise().then(reportUponEvaluation); - function reportUponEvaluation() { - target.consoleModel.dispatchEventToListeners( + Common.console.showPromise().then(() => { + this.dispatchEventToListeners( SDK.ConsoleModel.Events.CommandEvaluated, {result: result, text: requestedText, commandMessage: commandMessage, exceptionDetails: exceptionDetails}); - } + }); } /** @@ -133,7 +157,7 @@ if (looksLikeAnObjectLiteral(text)) text = '(' + text + ')'; - executionContext.evaluate(text, 'console', useCommandLineAPI, false, false, true, true, printResult); + executionContext.evaluate(text, 'console', useCommandLineAPI, false, false, true, true, printResult.bind(this)); Host.userMetrics.actionTaken(Host.UserMetrics.Action.ConsoleEvaluated); } @@ -145,11 +169,20 @@ return; if (msg.source === SDK.ConsoleMessage.MessageSource.ConsoleAPI && msg.type === SDK.ConsoleMessage.MessageType.Clear) - this.clear(); + this._clear(); this._messages.push(msg); - if (msg._exceptionId) - this._messageByExceptionId.set(msg._exceptionId, msg); + if (msg._exceptionId && msg.target()) { + // TODO(dgozman): make target non-nullable, as we only have messages without a target + // internally in ConsoleView. + var target = /** @type {!SDK.Target} */ (msg.target()); + var targetMap = this._messageByExceptionId.get(target); + if (!targetMap) { + targetMap = new Map(); + this._messageByExceptionId.set(target, targetMap); + } + targetMap.set(msg._exceptionId, msg); + } this._incrementErrorWarningCount(msg); this.dispatchEventToListeners(SDK.ConsoleModel.Events.MessageAdded, msg); } @@ -159,29 +192,32 @@ */ _logEntryAdded(event) { var consoleMessage = new SDK.ConsoleMessage( - this.target(), event.entry.source, event.entry.level, event.entry.text, undefined, event.entry.url, + event.logModel.target(), event.entry.source, event.entry.level, event.entry.text, undefined, event.entry.url, event.entry.lineNumber, undefined, event.entry.networkRequestId, undefined, event.entry.stackTrace, event.entry.timestamp, undefined, undefined, event.entry.workerId); this.addMessage(consoleMessage); } /** + * @param {!SDK.RuntimeModel} runtimeModel * @param {!Common.Event} event */ - _exceptionThrown(event) { + _exceptionThrown(runtimeModel, event) { var exceptionWithTimestamp = /** @type {!SDK.RuntimeModel.ExceptionWithTimestamp} */ (event.data); var consoleMessage = SDK.ConsoleMessage.fromException( - this.target(), exceptionWithTimestamp.details, undefined, exceptionWithTimestamp.timestamp, undefined); + runtimeModel.target(), exceptionWithTimestamp.details, undefined, exceptionWithTimestamp.timestamp, undefined); consoleMessage.setExceptionId(exceptionWithTimestamp.details.exceptionId); this.addMessage(consoleMessage); } /** + * @param {!SDK.RuntimeModel} runtimeModel * @param {!Common.Event} event */ - _exceptionRevoked(event) { + _exceptionRevoked(runtimeModel, event) { var exceptionId = /** @type {number} */ (event.data); - var exceptionMessage = this._messageByExceptionId.get(exceptionId); + var targetMap = this._messageByExceptionId.get(runtimeModel.target()); + var exceptionMessage = targetMap ? targetMap.get(exceptionId) : null; if (!exceptionMessage) return; this._errors--; @@ -190,9 +226,10 @@ } /** + * @param {!SDK.RuntimeModel} runtimeModel * @param {!Common.Event} event */ - _consoleAPICalled(event) { + _consoleAPICalled(runtimeModel, event) { var call = /** @type {!SDK.RuntimeModel.ConsoleAPICall} */ (event.data); var level = SDK.ConsoleMessage.MessageLevel.Info; if (call.type === SDK.ConsoleMessage.MessageType.Debug) @@ -210,7 +247,7 @@ message = call.args[0].description; var callFrame = call.stackTrace && call.stackTrace.callFrames.length ? call.stackTrace.callFrames[0] : null; var consoleMessage = new SDK.ConsoleMessage( - this.target(), SDK.ConsoleMessage.MessageSource.ConsoleAPI, level, + runtimeModel.target(), SDK.ConsoleMessage.MessageSource.ConsoleAPI, level, /** @type {string} */ (message), call.type, callFrame ? callFrame.url : undefined, callFrame ? callFrame.lineNumber : undefined, callFrame ? callFrame.columnNumber : undefined, undefined, call.args, call.stackTrace, call.timestamp, call.executionContextId, undefined); @@ -222,7 +259,7 @@ */ _mainFrameStartedLoading(event) { if (!Common.moduleSetting('preserveConsoleLog').get()) - this.clear(); + this._clear(); } /** @@ -234,31 +271,34 @@ } /** + * @param {!SDK.CPUProfilerModel} cpuProfilerModel * @param {!Common.Event} event */ - _consoleProfileStarted(event) { + _consoleProfileStarted(cpuProfilerModel, event) { var data = /** @type {!SDK.CPUProfilerModel.EventData} */ (event.data); this._addConsoleProfileMessage( - SDK.ConsoleMessage.MessageType.Profile, data.scriptLocation, + cpuProfilerModel, SDK.ConsoleMessage.MessageType.Profile, data.scriptLocation, Common.UIString('Profile \'%s\' started.', data.title)); } /** + * @param {!SDK.CPUProfilerModel} cpuProfilerModel * @param {!Common.Event} event */ - _consoleProfileFinished(event) { + _consoleProfileFinished(cpuProfilerModel, event) { var data = /** @type {!SDK.CPUProfilerModel.EventData} */ (event.data); this._addConsoleProfileMessage( - SDK.ConsoleMessage.MessageType.ProfileEnd, data.scriptLocation, + cpuProfilerModel, SDK.ConsoleMessage.MessageType.ProfileEnd, data.scriptLocation, Common.UIString('Profile \'%s\' finished.', data.title)); } /** + * @param {!SDK.CPUProfilerModel} cpuProfilerModel * @param {string} type * @param {!SDK.DebuggerModel.Location} scriptLocation * @param {string} messageText */ - _addConsoleProfileMessage(type, scriptLocation, messageText) { + _addConsoleProfileMessage(cpuProfilerModel, type, scriptLocation, messageText) { var stackTrace = [{ functionName: '', scriptId: scriptLocation.scriptId, @@ -267,17 +307,18 @@ columnNumber: scriptLocation.columnNumber || 0 }]; this.addMessage(new SDK.ConsoleMessage( - this.target(), SDK.ConsoleMessage.MessageSource.ConsoleAPI, SDK.ConsoleMessage.MessageLevel.Info, messageText, - type, undefined, undefined, undefined, undefined, stackTrace)); + cpuProfilerModel.target(), SDK.ConsoleMessage.MessageSource.ConsoleAPI, SDK.ConsoleMessage.MessageLevel.Info, + messageText, type, undefined, undefined, undefined, undefined, stackTrace)); } /** + * @param {!SDK.NetworkManager} networkManager * @param {!Common.Event} event */ - _networkWarningGenerated(event) { + _networkWarningGenerated(networkManager, event) { var warning = /** @type {!SDK.NetworkManager.Warning} */ (event.data); this.addMessage(new SDK.ConsoleMessage( - this.target(), SDK.ConsoleMessage.MessageSource.Network, SDK.ConsoleMessage.MessageLevel.Warning, + networkManager.target(), SDK.ConsoleMessage.MessageSource.Network, SDK.ConsoleMessage.MessageLevel.Warning, warning.message, undefined, undefined, undefined, undefined, warning.requestId)); } @@ -305,17 +346,16 @@ } requestClearMessages() { - var logModel = this.target().model(SDK.LogModel); - if (logModel) + for (var logModel of SDK.targetManager.models(SDK.LogModel)) logModel.requestClear(); - this.clear(); - this.target().runtimeModel.discardConsoleEntries(); + for (var runtimeModel of SDK.targetManager.models(SDK.RuntimeModel)) + runtimeModel.discardConsoleEntries(); + this._clear(); } - clear() { + _clear() { this._messages = []; this._messageByExceptionId.clear(); - // TODO(dgozman): clear exceptions and console api entries in runtimeModel. this._errors = 0; this._warnings = 0; this.dispatchEventToListeners(SDK.ConsoleModel.Events.ConsoleCleared); @@ -336,8 +376,6 @@ } }; -SDK.SDKModel.register(SDK.ConsoleModel, SDK.Target.Capability.None); - /** @enum {symbol} */ SDK.ConsoleModel.Events = { ConsoleCleared: Symbol('ConsoleCleared'), @@ -632,82 +670,9 @@ return 3; }; -/** - * @implements {SDK.TargetManager.Observer} - * @unrestricted - */ -SDK.MultitargetConsoleModel = class extends Common.Object { - constructor() { - super(); - SDK.targetManager.observeTargets(this); - SDK.targetManager.addModelListener( - SDK.ConsoleModel, SDK.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this); - SDK.targetManager.addModelListener( - SDK.ConsoleModel, SDK.ConsoleModel.Events.MessageUpdated, this._consoleMessageUpdated, this); - SDK.targetManager.addModelListener( - SDK.ConsoleModel, SDK.ConsoleModel.Events.CommandEvaluated, this._commandEvaluated, this); - } - - /** - * @override - * @param {!SDK.Target} target - */ - targetAdded(target) { - if (!this._mainTarget) { - this._mainTarget = target; - target.consoleModel.addEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); - } - } - - /** - * @override - * @param {!SDK.Target} target - */ - targetRemoved(target) { - if (this._mainTarget === target) { - delete this._mainTarget; - target.consoleModel.removeEventListener(SDK.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); - } - } - - /** - * @return {!Array.<!SDK.ConsoleMessage>} - */ - messages() { - var targets = SDK.targetManager.targets(); - var result = []; - for (var i = 0; i < targets.length; ++i) - result = result.concat(targets[i].consoleModel.messages()); - return result; - } - - _consoleCleared() { - this.dispatchEventToListeners(SDK.ConsoleModel.Events.ConsoleCleared); - } - - /** - * @param {!Common.Event} event - */ - _consoleMessageAdded(event) { - this.dispatchEventToListeners(SDK.ConsoleModel.Events.MessageAdded, event.data); - } - - /** - * @param {!Common.Event} event - */ - _consoleMessageUpdated(event) { - this.dispatchEventToListeners(SDK.ConsoleModel.Events.MessageUpdated, event.data); - } - - /** - * @param {!Common.Event} event - */ - _commandEvaluated(event) { - this.dispatchEventToListeners(SDK.ConsoleModel.Events.CommandEvaluated, event.data); - } -}; +SDK.ConsoleModel._events = Symbol('SDK.ConsoleModel.events'); /** - * @type {!SDK.MultitargetConsoleModel} + * @type {!SDK.ConsoleModel} */ -SDK.multitargetConsoleModel; +SDK.consoleModel;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/LogModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/LogModel.js index 57b1bdd..66dabf7d 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/LogModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/LogModel.js
@@ -28,7 +28,7 @@ * @param {!Protocol.Log.LogEntry} payload */ entryAdded(payload) { - this.emit(new SDK.LogModel.EntryAddedEvent(payload)); + this.emit(new SDK.LogModel.EntryAddedEvent(this, payload)); } requestClear() { @@ -41,9 +41,11 @@ /** @implements {Common.Emittable} */ SDK.LogModel.EntryAddedEvent = class { /** + * @param {!SDK.LogModel} logModel * @param {!Protocol.Log.LogEntry} entry */ - constructor(entry) { + constructor(logModel, entry) { + this.logModel = logModel; this.entry = entry; } };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js index c40b739e..25eb04cd 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -253,8 +253,6 @@ target.runtimeModel = /** @type {!SDK.RuntimeModel} */ (target.model(SDK.RuntimeModel)); target.model(SDK.DebuggerModel); target.model(SDK.LogModel); - /** @type {!SDK.ConsoleModel} */ - target.consoleModel = /** @type {!SDK.ConsoleModel} */ (target.model(SDK.ConsoleModel)); target.model(SDK.DOMModel); target.model(SDK.CSSModel); target.model(SDK.CPUProfilerModel);
diff --git a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js index ca8b6ca..c25cf7c 100644 --- a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js +++ b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
@@ -278,7 +278,7 @@ var consoleMessage = new SDK.ConsoleMessage( target, SDK.ConsoleMessage.MessageSource.JS, SDK.ConsoleMessage.MessageLevel.Info, '', undefined, sourceURL, undefined, undefined, undefined, [result], undefined, undefined, undefined, scriptId); - target.consoleModel.addMessage(consoleMessage); + SDK.consoleModel.addMessage(consoleMessage); } /** @@ -287,7 +287,7 @@ * @param {?string=} sourceURL */ _printRunOrCompileScriptResultFailure(target, exceptionDetails, sourceURL) { - target.consoleModel.addMessage( + SDK.consoleModel.addMessage( SDK.ConsoleMessage.fromException(target, exceptionDetails, undefined, undefined, sourceURL || undefined)); }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js index 735c0da..695c0a1 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -956,7 +956,7 @@ if (wasThrown || !result || result.type !== 'string') { failedToSave(result); } else { - SDK.ConsoleModel.evaluateCommandInConsole( + SDK.consoleModel.evaluateCommandInConsole( /** @type {!SDK.ExecutionContext} */ (currentExecutionContext), result.value, /* useCommandLineAPI */ false); } @@ -1268,7 +1268,7 @@ var text = frame.textEditor.text(frame.textEditor.selection()); var executionContext = UI.context.flavor(SDK.ExecutionContext); if (executionContext) - SDK.ConsoleModel.evaluateCommandInConsole(executionContext, text, /* useCommandLineAPI */ true); + SDK.consoleModel.evaluateCommandInConsole(executionContext, text, /* useCommandLineAPI */ true); } return true; }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp index caf7682..36bad05 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -731,7 +731,7 @@ if (node->isConnected() && node->isElementNode()) { RefPtr<ComputedStyle> style = document->ensureStyleResolver().styleForElement(toElement(node)); - return style->display() == EDisplay::None || + return style->display() == EDisplay::kNone || style->visibility() != EVisibility::kVisible; } }
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl index 8e1b0cb9..1ff409c 100644 --- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl +++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
@@ -50,7 +50,7 @@ [CallWith=ScriptState] MediaStreamTrack clone(); [ImplementedAs=stopTrack, RaisesException] void stop(); - [RuntimeEnabled=ImageCapture] MediaTrackCapabilities getCapabilities(); + [RuntimeEnabled=MediaTrackCapabilities] MediaTrackCapabilities getCapabilities(); [RuntimeEnabled=MediaConstraints] MediaTrackConstraints getConstraints(); [RuntimeEnabled=MediaGetSettings] MediaTrackSettings getSettings(); };
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 index 95748be8..cc882ac 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -541,6 +541,10 @@ name: "MediaGetSettings", status: "stable", }, + { + name: "MediaQueryShape", + status: "experimental", + }, // MediaSession is enabled by default on Android only. // TODO(rbyers): Add parameter to specify platform. { @@ -560,11 +564,12 @@ status: "experimental", }, { - name: "MediaQueryShape", + name: "MediaStreamTrackContentHint", status: "experimental", }, { - name: "MediaStreamTrackContentHint", + name: "MediaTrackCapabilities", + implied_by: ["ImageCapture"], status: "experimental", }, {
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollTypes.h b/third_party/WebKit/Source/platform/scroll/ScrollTypes.h index 32d22c8..b7e117f5 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollTypes.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollTypes.h
@@ -43,8 +43,12 @@ return ScrollOffset(p.x(), p.y()); } +// Platform overlay scrollbars are controlled and painted by the operating +// system (e.g., OSX and Android). CSS overlay scrollbars are created by +// setting overflow:overlay, and they are painted by chromium. enum OverlayScrollbarClipBehavior { - IgnoreOverlayScrollbarSize, + IgnorePlatformOverlayScrollbarSize, + IgnorePlatformAndCSSOverlayScrollbarSize, ExcludeOverlayScrollbarSizeForHitTesting };
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp index 9beeba9..3991c98 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -635,7 +635,7 @@ int ScrollableArea::verticalScrollbarWidth( OverlayScrollbarClipBehavior behavior) const { - DCHECK_EQ(behavior, IgnoreOverlayScrollbarSize); + DCHECK_EQ(behavior, IgnorePlatformOverlayScrollbarSize); if (Scrollbar* verticalBar = verticalScrollbar()) return !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0; return 0; @@ -643,7 +643,7 @@ int ScrollableArea::horizontalScrollbarHeight( OverlayScrollbarClipBehavior behavior) const { - DCHECK_EQ(behavior, IgnoreOverlayScrollbarSize); + DCHECK_EQ(behavior, IgnorePlatformOverlayScrollbarSize); if (Scrollbar* horizontalBar = horizontalScrollbar()) return !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0; return 0;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h index 5c74eff..a284ce6 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -335,9 +335,9 @@ IntSize excludeScrollbars(const IntSize&) const; virtual int verticalScrollbarWidth( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize) const; virtual int horizontalScrollbarHeight( - OverlayScrollbarClipBehavior = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarClipBehavior = IgnorePlatformOverlayScrollbarSize) const; // Returns the widget associated with this ScrollableArea. virtual FrameViewBase* getFrameViewBase() { return nullptr; }
diff --git a/third_party/WebKit/Source/platform/wtf/AddressSanitizer.h b/third_party/WebKit/Source/platform/wtf/AddressSanitizer.h new file mode 100644 index 0000000..5fd627a --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/AddressSanitizer.h
@@ -0,0 +1,42 @@ +// 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 WTF_AddressSanitizer_h +#define WTF_AddressSanitizer_h +// TODO(kojii): This file will need to be renamed, because it's no more +// specific to AddressSanitizer. + +#include "platform/wtf/build_config.h" + +// TODO(sof): Add SyZyASan support? +#if defined(ADDRESS_SANITIZER) +#include <sanitizer/asan_interface.h> +#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +#else +#define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) +#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) +#define NO_SANITIZE_ADDRESS +#endif + +#if defined(LEAK_SANITIZER) +#include <sanitizer/lsan_interface.h> +#else +#define __lsan_register_root_region(addr, size) ((void)(addr), (void)(size)) +#define __lsan_unregister_root_region(addr, size) ((void)(addr), (void)(size)) +#endif + +#if defined(MEMORY_SANITIZER) +#include <sanitizer/msan_interface.h> +#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) +#else +#define NO_SANITIZE_MEMORY +#endif + +#if defined(THREAD_SANITIZER) +#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) +#else +#define NO_SANITIZE_THREAD +#endif + +#endif // WTF_AddressSanitizer_h
diff --git a/third_party/WebKit/Source/platform/wtf/Alignment.h b/third_party/WebKit/Source/platform/wtf/Alignment.h new file mode 100644 index 0000000..638f81a --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/Alignment.h
@@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef WTF_Alignment_h +#define WTF_Alignment_h + +#include "platform/wtf/Compiler.h" +#include <algorithm> +#include <stdint.h> +#include <utility> + +namespace WTF { + +#if COMPILER(GCC) +#define WTF_ALIGN_OF(type) __alignof__(type) +#define WTF_ALIGNED(variable_type, variable, n) \ + variable_type variable __attribute__((__aligned__(n))) +#elif COMPILER(MSVC) +#define WTF_ALIGN_OF(type) __alignof(type) +#define WTF_ALIGNED(variable_type, variable, n) \ + __declspec(align(n)) variable_type variable +#else +#error WTF_ALIGN macros need alignment control. +#endif + +#if COMPILER(GCC) +typedef char __attribute__((__may_alias__)) AlignedBufferChar; // NOLINT +#else +typedef char AlignedBufferChar; +#endif + +template <size_t size, size_t alignment> +struct AlignedBuffer; +template <size_t size> +struct AlignedBuffer<size, 1> { + AlignedBufferChar buffer[size]; +}; +template <size_t size> +struct AlignedBuffer<size, 2> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 2); +}; +template <size_t size> +struct AlignedBuffer<size, 4> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 4); +}; +template <size_t size> +struct AlignedBuffer<size, 8> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 8); +}; +template <size_t size> +struct AlignedBuffer<size, 16> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 16); +}; +template <size_t size> +struct AlignedBuffer<size, 32> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 32); +}; +template <size_t size> +struct AlignedBuffer<size, 64> { + WTF_ALIGNED(AlignedBufferChar, buffer[size], 64); +}; + +template <size_t size, size_t alignment> +void swap(AlignedBuffer<size, alignment>& a, + AlignedBuffer<size, alignment>& b) { + for (size_t i = 0; i < size; ++i) + std::swap(a.buffer[i], b.buffer[i]); +} + +template <uintptr_t mask> +inline bool isAlignedTo(const void* pointer) { + return !(reinterpret_cast<uintptr_t>(pointer) & mask); +} + +} // namespace WTF + +#endif // WTF_Alignment_h
diff --git a/third_party/WebKit/Source/platform/wtf/AutoReset.h b/third_party/WebKit/Source/platform/wtf/AutoReset.h new file mode 100644 index 0000000..b74eaf8 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/AutoReset.h
@@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AutoReset_h +#define AutoReset_h + +#include "base/auto_reset.h" + +namespace WTF { + +// WTF::AutoReset is base::AutoReset. See base/auto_reset.h for documentation. + +template <typename T> +using AutoReset = base::AutoReset<T>; + +} // namespace WTF + +using WTF::AutoReset; + +#endif
diff --git a/third_party/WebKit/Source/platform/wtf/BUILD.gn b/third_party/WebKit/Source/platform/wtf/BUILD.gn index 6873bdb..879124f3 100644 --- a/third_party/WebKit/Source/platform/wtf/BUILD.gn +++ b/third_party/WebKit/Source/platform/wtf/BUILD.gn
@@ -59,9 +59,29 @@ component("platform_wtf") { sources = [ + "AddressSanitizer.h", + "Alignment.h", + "AutoReset.h", + "BitwiseOperations.h", + "ByteSwap.h", + "CPU.h", + "CheckedNumeric.h", + "Compiler.h", + "ConditionalDestructor.h", + "ContainerAnnotations.h", "CryptographicallyRandomNumber.cpp", "CryptographicallyRandomNumber.h", + "CurrentTime.cpp", + "CurrentTime.h", + "DynamicAnnotations.cpp", + "DynamicAnnotations.h", + "Forward.h", + "GetPtr.h", + "LeakAnnotations.h", + "Noncopyable.h", + "TypeTraits.h", "WTFExport.h", + "build_config.h", ] configs += [
diff --git a/third_party/WebKit/Source/wtf/CurrentTime.cpp b/third_party/WebKit/Source/platform/wtf/BitwiseOperations.h similarity index 64% copy from third_party/WebKit/Source/wtf/CurrentTime.cpp copy to third_party/WebKit/Source/platform/wtf/BitwiseOperations.h index 71ffbcc..8d5d86a 100644 --- a/third_party/WebKit/Source/wtf/CurrentTime.cpp +++ b/third_party/WebKit/Source/platform/wtf/BitwiseOperations.h
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2013 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,35 +28,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "wtf/CurrentTime.h" +// TODO(palmer): The only caller of this code in Blink is PartitionAlloc. When +// PA is moved to base, we can remove this file. +// https://bugs.chromium.org/p/chromium/issues/detail?id=632441 -#include "base/time/time.h" +#ifndef WTF_BitwiseOperations_h +#define WTF_BitwiseOperations_h + +#include "base/bits.h" +#include "platform/wtf/CPU.h" namespace WTF { -static TimeFunction mockTimeFunctionForTesting = nullptr; +using base::bits::CountLeadingZeroBits32; +using base::bits::CountLeadingZeroBitsSizeT; -double currentTime() { - if (mockTimeFunctionForTesting) - return mockTimeFunctionForTesting(); - return base::Time::Now().ToDoubleT(); -} - -double monotonicallyIncreasingTime() { - if (mockTimeFunctionForTesting) - return mockTimeFunctionForTesting(); - return base::TimeTicks::Now().ToInternalValue() / - static_cast<double>(base::Time::kMicrosecondsPerSecond); -} - -TimeFunction setTimeFunctionsForTesting(TimeFunction newFunction) { - TimeFunction oldFunction = mockTimeFunctionForTesting; - mockTimeFunctionForTesting = newFunction; - return oldFunction; -} - -TimeFunction getTimeFunctionForTesting() { - return mockTimeFunctionForTesting; -} +#if CPU(64BIT) +using base::bits::CountLeadingZeroBits64; +#endif } // namespace WTF + +#endif // WTF_BitwiseOperations_h
diff --git a/third_party/WebKit/Source/platform/wtf/ByteSwap.h b/third_party/WebKit/Source/platform/wtf/ByteSwap.h new file mode 100644 index 0000000..979f7ac --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/ByteSwap.h
@@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_ByteSwap_h +#define WTF_ByteSwap_h + +#include "platform/wtf/CPU.h" +#include "platform/wtf/Compiler.h" + +#include <stdint.h> + +#if COMPILER(MSVC) +#include <stdlib.h> +#endif + +namespace WTF { + +inline uint32_t wswap32(uint32_t x) { + return ((x & 0xffff0000) >> 16) | ((x & 0x0000ffff) << 16); +} + +#if COMPILER(MSVC) + +ALWAYS_INLINE uint64_t bswap64(uint64_t x) { + return _byteswap_uint64(x); +} +ALWAYS_INLINE uint32_t bswap32(uint32_t x) { + return _byteswap_ulong(x); +} +ALWAYS_INLINE uint16_t bswap16(uint16_t x) { + return _byteswap_ushort(x); +} + +#else + +ALWAYS_INLINE uint64_t bswap64(uint64_t x) { + return __builtin_bswap64(x); +} +ALWAYS_INLINE uint32_t bswap32(uint32_t x) { + return __builtin_bswap32(x); +} +ALWAYS_INLINE uint16_t bswap16(uint16_t x) { + return __builtin_bswap16(x); +} + +#endif + +#if CPU(64BIT) + +ALWAYS_INLINE size_t bswapuintptrt(size_t x) { + return bswap64(x); +} + +#else + +ALWAYS_INLINE size_t bswapuintptrt(size_t x) { + return bswap32(x); +} + +#endif + +} // namespace WTF + +#endif // WTF_ByteSwap_h
diff --git a/third_party/WebKit/Source/platform/wtf/CPU.h b/third_party/WebKit/Source/platform/wtf/CPU.h new file mode 100644 index 0000000..409b58c --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/CPU.h
@@ -0,0 +1,171 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_CPU_h +#define WTF_CPU_h + +#include "platform/wtf/Compiler.h" + +/* CPU() - the target CPU architecture */ +#define CPU(WTF_FEATURE) \ + (defined WTF_CPU_##WTF_FEATURE && WTF_CPU_##WTF_FEATURE) + +/* ==== CPU() - the target CPU architecture ==== */ + +/* This defines CPU(BIG_ENDIAN) or nothing, as appropriate. */ +/* This defines CPU(32BIT) or CPU(64BIT), as appropriate. */ + +/* CPU(X86) - i386 / x86 32-bit */ +#if defined(__i386__) || defined(i386) || defined(_M_IX86) || \ + defined(_X86_) || defined(__THW_INTEL) +#define WTF_CPU_X86 1 +#endif + +/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */ +#if defined(__x86_64__) || defined(_M_X64) +#define WTF_CPU_X86_64 1 +#define WTF_CPU_64BIT 1 +#endif + +/* CPU(ARM) - ARM, any version*/ +#define WTF_ARM_ARCH_AT_LEAST(N) \ + (CPU(ARM) && defined(WTF_ARM_ARCH_VERSION) && WTF_ARM_ARCH_VERSION >= N) + +#if defined(arm) || defined(__arm__) || defined(ARM) || defined(_ARM_) +#define WTF_CPU_ARM 1 + +#if defined(__ARMEB__) +#define WTF_CPU_BIG_ENDIAN 1 + +#elif !defined(__ARM_EABI__) && !defined(__EABI__) && !defined(__VFP_FP__) && \ + !defined(_WIN32_WCE) && !defined(ANDROID) +#define WTF_CPU_MIDDLE_ENDIAN 1 + +#endif + +/* Set WTF_ARM_ARCH_VERSION */ +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ + defined(__MARM_ARMV4__) +#define WTF_ARM_ARCH_VERSION 4 + +#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__MARM_ARMV5__) +#define WTF_ARM_ARCH_VERSION 5 + +#elif defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +#define WTF_ARM_ARCH_VERSION 5 + +#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ + defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \ + defined(__ARMV6__) +#define WTF_ARM_ARCH_VERSION 6 + +#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ + defined(__ARM_ARCH_7S__) +#define WTF_ARM_ARCH_VERSION 7 + +/* MSVC sets _M_ARM */ +#elif defined(_M_ARM) +#define WTF_ARM_ARCH_VERSION _M_ARM +#else +#define WTF_ARM_ARCH_VERSION 0 + +#endif + +/* Set WTF_THUMB_ARCH_VERSION */ +#if defined(__ARM_ARCH_4T__) +#define WTF_THUMB_ARCH_VERSION 1 + +#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +#define WTF_THUMB_ARCH_VERSION 2 + +#elif defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || \ + defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6M__) +#define WTF_THUMB_ARCH_VERSION 3 + +#elif defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_7__) || \ + defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7S__) +#define WTF_THUMB_ARCH_VERSION 4 + +#else +#define WTF_THUMB_ARCH_VERSION 0 +#endif + +/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */ +#if !defined(WTF_CPU_ARM_THUMB2) +#if defined(thumb2) || defined(__thumb2__) || \ + ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) +#define WTF_CPU_ARM_THUMB2 1 +#elif WTF_ARM_ARCH_AT_LEAST(4) +#define WTF_CPU_ARM_THUMB2 0 +#else +#error "Unsupported ARM architecture" +#endif +#endif /* !defined(WTF_CPU_ARM_THUMB2) */ + +#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON) +#define WTF_CPU_ARM_NEON 1 +#endif + +#if CPU(ARM_NEON) && \ + (COMPILER(CLANG) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4, 7, 0)) +// All NEON intrinsics usage can be disabled by this macro. +#define HAVE_ARM_NEON_INTRINSICS 1 +#endif + +#endif /* ARM */ + +/* CPU(ARM64) - AArch64 64-bit */ +#if defined(__aarch64__) +#define WTF_CPU_ARM64 1 +#define WTF_CPU_64BIT 1 +#endif + +/* CPU(MIPS), CPU(MIPS64) */ +#if defined(__mips__) && (__mips == 64) +#define WTF_CPU_MIPS64 1 +#define WTF_CPU_64BIT 1 +#elif defined(__mips__) +#define WTF_CPU_MIPS 1 +#endif + +#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) +// All MSA intrinsics usage can be disabled by this macro. +#define HAVE_MIPS_MSA_INTRINSICS 1 +#endif + +#if !defined(WTF_CPU_64BIT) +#define WTF_CPU_32BIT 1 +#endif + +#endif /* WTF_CPU_h */
diff --git a/third_party/WebKit/Source/platform/wtf/CheckedNumeric.h b/third_party/WebKit/Source/platform/wtf/CheckedNumeric.h new file mode 100644 index 0000000..f94ba48 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/CheckedNumeric.h
@@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_CheckedNumeric_h +#define WTF_CheckedNumeric_h + +/* See base/numerics/safe_math.h for usage. + */ +#include "base/numerics/safe_math.h" + +namespace WTF { +using base::CheckedNumeric; +} // namespace WTF + +using WTF::CheckedNumeric; + +#endif
diff --git a/third_party/WebKit/Source/platform/wtf/Compiler.h b/third_party/WebKit/Source/platform/wtf/Compiler.h new file mode 100644 index 0000000..1b81bb9 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/Compiler.h
@@ -0,0 +1,100 @@ +/* + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_Compiler_h +#define WTF_Compiler_h + +#include "base/compiler_specific.h" + +/* COMPILER() - the compiler being used to build the project */ +#define COMPILER(WTF_FEATURE) \ + (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE) + +/* ==== COMPILER() - the compiler being used to build the project ==== */ + +/* COMPILER(CLANG) - Clang */ +#if defined(__clang__) +#define WTF_COMPILER_CLANG 1 +#endif + +/* COMPILER(MSVC) - Microsoft Visual C++ (and Clang when compiling for Windows). + */ +#if defined(_MSC_VER) +#define WTF_COMPILER_MSVC 1 +#endif + +/* COMPILER(GCC) - GNU Compiler Collection (and Clang when compiling for + * platforms other than Windows). */ +#if defined(__GNUC__) +#define WTF_COMPILER_GCC 1 +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#define GCC_VERSION_AT_LEAST(major, minor, patch) \ + (GCC_VERSION >= (major * 10000 + minor * 100 + patch)) +#else +/* Define this for !GCC compilers, just so we can write things like + * GCC_VERSION_AT_LEAST(4, 1, 0). */ +#define GCC_VERSION_AT_LEAST(major, minor, patch) 0 +#endif + +/* ==== Compiler features ==== */ + +/* NEVER_INLINE */ + +// TODO(palmer): Remove this and update callers to use NOINLINE from Chromium +// base. https://bugs.chromium.org/p/chromium/issues/detail?id=632441 +#define NEVER_INLINE NOINLINE + +/* OBJC_CLASS */ + +#ifndef OBJC_CLASS +#ifdef __OBJC__ +#define OBJC_CLASS @class +#else +#define OBJC_CLASS class +#endif +#endif + +/* WTF_PRETTY_FUNCTION */ + +#if COMPILER(GCC) +#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#elif COMPILER(MSVC) +#define WTF_PRETTY_FUNCTION __FUNCSIG__ +#else +#define WTF_PRETTY_FUNCTION __func__ +#endif + +/* NO_SANITIZE_UNRELATED_CAST - Disable runtime checks related to casts between + * unrelated objects (-fsanitize=cfi-unrelated-cast or -fsanitize=vptr). */ + +#if COMPILER(CLANG) +#define NO_SANITIZE_UNRELATED_CAST \ + __attribute__((no_sanitize("cfi-unrelated-cast", "vptr"))) +#else +#define NO_SANITIZE_UNRELATED_CAST +#endif + +#endif /* WTF_Compiler_h */
diff --git a/third_party/WebKit/Source/platform/wtf/ConditionalDestructor.h b/third_party/WebKit/Source/platform/wtf/ConditionalDestructor.h new file mode 100644 index 0000000..c2fdd1c5 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/ConditionalDestructor.h
@@ -0,0 +1,28 @@ +// 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 ConditionalDestructor_h +#define ConditionalDestructor_h + +namespace WTF { + +// ConditionalDestructor defines the destructor of the derived object. +// This base is used in order to completely avoid creating a destructor +// for an object that does not need to be destructed. By doing so, +// the clang compiler will have correct information about whether or not +// the object has a trivial destructor. +// Note: the derived object MUST release all its recources at the finalize() +// method. +template <typename Derived, bool noDestructor> +class ConditionalDestructor { + public: + ~ConditionalDestructor() { static_cast<Derived*>(this)->finalize(); } +}; + +template <typename Derived> +class ConditionalDestructor<Derived, true> {}; + +} // namespace WTF + +#endif // ConditionalDestructor_h
diff --git a/third_party/WebKit/Source/platform/wtf/ContainerAnnotations.h b/third_party/WebKit/Source/platform/wtf/ContainerAnnotations.h new file mode 100644 index 0000000..d0b7459d --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/ContainerAnnotations.h
@@ -0,0 +1,44 @@ +// 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 WTF_ContainerAnnotations_h +#define WTF_ContainerAnnotations_h + +#include "platform/wtf/AddressSanitizer.h" +#include "platform/wtf/CPU.h" + +// TODO(ochang): Remove the CPU(X86_64) condition to enable this for X86 once +// the crashes there have been fixed: http://crbug.com/461406 +#if defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) +#define ANNOTATE_CONTIGUOUS_CONTAINER +#define ANNOTATE_NEW_BUFFER(buffer, capacity, newSize) \ + if (buffer) { \ + __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ + (buffer) + (capacity), \ + (buffer) + (newSize)); \ + } +#define ANNOTATE_DELETE_BUFFER(buffer, capacity, oldSize) \ + if (buffer) { \ + __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ + (buffer) + (oldSize), \ + (buffer) + (capacity)); \ + } +#define ANNOTATE_CHANGE_SIZE(buffer, capacity, oldSize, newSize) \ + if (buffer) { \ + __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ + (buffer) + (oldSize), \ + (buffer) + (newSize)); \ + } +#define ANNOTATE_CHANGE_CAPACITY(buffer, oldCapacity, bufferSize, newCapacity) \ + ANNOTATE_DELETE_BUFFER(buffer, oldCapacity, bufferSize); \ + ANNOTATE_NEW_BUFFER(buffer, newCapacity, bufferSize); +// Annotations require buffers to begin on an 8-byte boundary. +#else // defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) +#define ANNOTATE_NEW_BUFFER(buffer, capacity, newSize) +#define ANNOTATE_DELETE_BUFFER(buffer, capacity, oldSize) +#define ANNOTATE_CHANGE_SIZE(buffer, capacity, oldSize, newSize) +#define ANNOTATE_CHANGE_CAPACITY(buffer, oldCapacity, bufferSize, newCapacity) +#endif // defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) + +#endif // WTF_ContainerAnnotations_h
diff --git a/third_party/WebKit/Source/wtf/CurrentTime.cpp b/third_party/WebKit/Source/platform/wtf/CurrentTime.cpp similarity index 98% rename from third_party/WebKit/Source/wtf/CurrentTime.cpp rename to third_party/WebKit/Source/platform/wtf/CurrentTime.cpp index 71ffbcc..13ec076 100644 --- a/third_party/WebKit/Source/wtf/CurrentTime.cpp +++ b/third_party/WebKit/Source/platform/wtf/CurrentTime.cpp
@@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "wtf/CurrentTime.h" +#include "platform/wtf/CurrentTime.h" #include "base/time/time.h"
diff --git a/third_party/WebKit/Source/platform/wtf/CurrentTime.h b/third_party/WebKit/Source/platform/wtf/CurrentTime.h new file mode 100644 index 0000000..705a2c9 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/CurrentTime.h
@@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CurrentTime_h +#define CurrentTime_h + +#include "platform/wtf/WTFExport.h" + +namespace WTF { + +// Returns the current UTC time in seconds, counted from January 1, 1970. +// Precision varies depending on platform but is usually as good or better +// than a millisecond. +WTF_EXPORT double currentTime(); + +// Same thing, in milliseconds. +inline double currentTimeMS() { + return currentTime() * 1000.0; +} + +// Provides a monotonically increasing time in seconds since an arbitrary point +// in the past. On unsupported platforms, this function only guarantees the +// result will be non-decreasing. +WTF_EXPORT double monotonicallyIncreasingTime(); + +// Same thing, in milliseconds. +inline double monotonicallyIncreasingTimeMS() { + return monotonicallyIncreasingTime() * 1000.0; +} + +using TimeFunction = double (*)(); + +// Make all the time functions (currentTime(), monotonicallyIncreasingTime(), +// systemTraceTime()) return the result of the supplied function. Returns the +// pointer to the old time function. For both setting and getting, nullptr +// means using the default timing function returning the actual time. +WTF_EXPORT TimeFunction setTimeFunctionsForTesting(TimeFunction); + +// Allows wtf/Time.h to use the same mock time function +WTF_EXPORT TimeFunction getTimeFunctionForTesting(); + +} // namespace WTF + +using WTF::currentTime; +using WTF::currentTimeMS; +using WTF::monotonicallyIncreasingTime; +using WTF::monotonicallyIncreasingTimeMS; +using WTF::TimeFunction; +using WTF::setTimeFunctionsForTesting; + +#endif // CurrentTime_h
diff --git a/third_party/WebKit/Source/wtf/DynamicAnnotations.cpp b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp similarity index 97% rename from third_party/WebKit/Source/wtf/DynamicAnnotations.cpp rename to third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp index ae6b8879..f8a84a2c 100644 --- a/third_party/WebKit/Source/wtf/DynamicAnnotations.cpp +++ b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp
@@ -24,7 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "DynamicAnnotations.h" +#include "platform/wtf/DynamicAnnotations.h" #if USE(DYNAMIC_ANNOTATIONS) && !USE(DYNAMIC_ANNOTATIONS_NOIMPL)
diff --git a/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h new file mode 100644 index 0000000..8c5d939 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h
@@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_DynamicAnnotations_h +#define WTF_DynamicAnnotations_h + +/* This file defines dynamic annotations for use with dynamic analysis + * tool such as ThreadSanitizer, Valgrind, etc. + * + * Dynamic annotation is a source code annotation that affects + * the generated code (that is, the annotation is not a comment). + * Each such annotation is attached to a particular + * instruction and/or to a particular object (address) in the program. + * + * By using dynamic annotations a developer can give more details to the dynamic + * analysis tool to improve its precision. + * + * In C/C++ program the annotations are represented as C macros. + * With the default build flags, these macros are empty, hence don't affect + * performance of a compiled binary. + * If dynamic annotations are enabled, they just call no-op functions. + * The dynamic analysis tools can intercept these functions and replace them + * with their own implementations. + * + * See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations for more + * information. + */ + +#include "platform/wtf/WTFExport.h" +#include "platform/wtf/build_config.h" + +#if USE(DYNAMIC_ANNOTATIONS) +/* Tell data race detector that we're not interested in reports on the given + * address range. */ +#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + WTFAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) +#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) \ + WTFAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, sizeof(*(pointer)), \ + description) + +/* Annotations for user-defined synchronization mechanisms. + * These annotations can be used to define happens-before arcs in user-defined + * synchronization mechanisms: the race detector will infer an arc from + * the former to the latter when they share the same argument pointer. + * + * The most common case requiring annotations is atomic reference counting: + * bool deref() { + * ANNOTATE_HAPPENS_BEFORE(&m_refCount); + * if (!atomicDecrement(&m_refCount)) { + * // m_refCount is now 0 + * ANNOTATE_HAPPENS_AFTER(&m_refCount); + * // "return true; happens-after each atomicDecrement of m_refCount" + * return true; + * } + * return false; + * } + */ +#define WTF_ANNOTATE_HAPPENS_BEFORE(address) \ + WTFAnnotateHappensBefore(__FILE__, __LINE__, address) +#define WTF_ANNOTATE_HAPPENS_AFTER(address) \ + WTFAnnotateHappensAfter(__FILE__, __LINE__, address) + +#ifdef __cplusplus +extern "C" { +#endif +/* Don't use these directly, use the above macros instead. */ +WTF_EXPORT void WTFAnnotateBenignRaceSized(const char* file, + int line, + const volatile void* memory, + long size, + const char* description); +WTF_EXPORT void WTFAnnotateHappensBefore(const char* file, + int line, + const volatile void* address); +WTF_EXPORT void WTFAnnotateHappensAfter(const char* file, + int line, + const volatile void* address); +#ifdef __cplusplus +} // extern "C" +#endif + +#else // USE(DYNAMIC_ANNOTATIONS) +/* These macros are empty when dynamic annotations are not enabled so you can + * use them without affecting the performance of release binaries. */ +#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) +#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) +#define WTF_ANNOTATE_HAPPENS_BEFORE(address) +#define WTF_ANNOTATE_HAPPENS_AFTER(address) +#endif // USE(DYNAMIC_ANNOTATIONS) + +#endif // WTF_DynamicAnnotations_h
diff --git a/third_party/WebKit/Source/platform/wtf/Forward.h b/third_party/WebKit/Source/platform/wtf/Forward.h new file mode 100644 index 0000000..c6d12c1 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/Forward.h
@@ -0,0 +1,84 @@ +/* + * Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef WTF_Forward_h +#define WTF_Forward_h + +#include "platform/wtf/Compiler.h" +#include <stddef.h> + +namespace WTF { + +template <typename T> +class PassRefPtr; +template <typename T> +class RefPtr; +template <typename T> +class StringBuffer; +template <typename T, size_t inlineCapacity, typename Allocator> +class Vector; + +class ArrayBuffer; +class ArrayBufferView; +class ArrayPiece; +class AtomicString; +class CString; +class Float32Array; +class Float64Array; +class Int8Array; +class Int16Array; +class Int32Array; +class OrdinalNumber; +class String; +class StringBuilder; +class StringImpl; +class StringView; +class Uint8Array; +class Uint8ClampedArray; +class Uint16Array; +class Uint32Array; + +} // namespace WTF + +using WTF::PassRefPtr; +using WTF::RefPtr; +using WTF::Vector; + +using WTF::ArrayBuffer; +using WTF::ArrayBufferView; +using WTF::ArrayPiece; +using WTF::AtomicString; +using WTF::CString; +using WTF::Float32Array; +using WTF::Float64Array; +using WTF::Int8Array; +using WTF::Int16Array; +using WTF::Int32Array; +using WTF::String; +using WTF::StringBuffer; +using WTF::StringBuilder; +using WTF::StringImpl; +using WTF::StringView; +using WTF::Uint8Array; +using WTF::Uint8ClampedArray; +using WTF::Uint16Array; +using WTF::Uint32Array; + +#endif // WTF_Forward_h
diff --git a/third_party/WebKit/Source/platform/wtf/GetPtr.h b/third_party/WebKit/Source/platform/wtf/GetPtr.h new file mode 100644 index 0000000..f211f20 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/GetPtr.h
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef WTF_GetPtr_h +#define WTF_GetPtr_h + +namespace WTF { + +template <typename T> +inline T* getPtr(T* p) { + return p; +} + +template <typename T> +inline T* getPtr(T& p) { + return &p; +} + +} // namespace WTF + +#endif // WTF_GetPtr_h
diff --git a/third_party/WebKit/Source/platform/wtf/LeakAnnotations.h b/third_party/WebKit/Source/platform/wtf/LeakAnnotations.h new file mode 100644 index 0000000..82321412 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/LeakAnnotations.h
@@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_LeakAnnotations_h +#define WTF_LeakAnnotations_h + +// This file defines macros for working with LeakSanitizer, allowing memory +// and allocations to be registered as exempted from LSan consideration. + +#include "platform/wtf/Noncopyable.h" +#if defined(LEAK_SANITIZER) +#include "platform/wtf/AddressSanitizer.h" +#include "platform/wtf/TypeTraits.h" +#endif + +namespace WTF { + +#if defined(LEAK_SANITIZER) +class LeakSanitizerDisabler { + WTF_MAKE_NONCOPYABLE(LeakSanitizerDisabler); + + public: + LeakSanitizerDisabler() { __lsan_disable(); } + + ~LeakSanitizerDisabler() { __lsan_enable(); } +}; + +// WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE: all allocations made in the +// current scope will be exempted from LSan consideration. Only to be +// used internal to wtf/, Blink should use LEAK_SANITIZER_DISABLED_SCOPE +// elsewhere. +// +// TODO(sof): once layering rules allow wtf/ to make use of the Oilpan +// infrastructure, remove this macro. +#define WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE \ + WTF::LeakSanitizerDisabler leakSanitizerDisabler; \ + static_cast<void>(0) + +// LEAK_SANITIZER_IGNORE_OBJECT(X): the heap object referenced by pointer X +// will be ignored by LSan. +// +// "Ignorance" means that LSan's reachability traversal is stopped short +// upon encountering an ignored memory chunk. Consequently, LSan will not +// scan an ignored memory chunk for live, reachable pointers. However, should +// those embedded pointers be reachable by some other path, they will be +// reported as leaking. +#define LEAK_SANITIZER_IGNORE_OBJECT(X) __lsan_ignore_object(X) + +// If the object pointed to by the static local is on the Oilpan heap, a strong +// Persistent<> is created to keep the pointed-to heap object alive. This makes +// both the Persistent<> and the heap object _reachable_ by LeakSanitizer's leak +// detection pass. We do not want these intentional leaks to be reported by +// LSan, hence the static local is registered with Oilpan +// (see RegisterStaticLocalReference<> below.) +// +// Upon Blink shutdown, all the registered statics are released and a final +// round of GCs are performed to sweep out their now-unreachable object graphs. +// The end result being a tidied heap that the LeakSanitizer can then scan to +// report real leaks. +// +// The CanRegisterStaticLocalReference<> and RegisterStaticLocalReference<> +// templates arrange for this -- for a class type T, a registerStatic() +// implementation is provided if "T* T::registerAsStaticReference(T*)" is a +// method on T (inherited or otherwise.) +// +// An empty, trivial registerStatic() method is provided for all other class +// types T. +template <typename T> +class CanRegisterStaticLocalReference { + typedef char YesType; + typedef struct NoType { char padding[8]; } NoType; + + // Check if class T has public method "T* registerAsStaticReference()". + template <typename V> + static YesType checkHasRegisterAsStaticReferenceMethod( + V* p, + typename std::enable_if<IsSubclass< + V, + typename std::remove_pointer<decltype( + p->registerAsStaticReference())>::type>::value>::type* = 0); + template <typename V> + static NoType checkHasRegisterAsStaticReferenceMethod(...); + + public: + static const bool value = + sizeof(YesType) + sizeof(T) == + sizeof(checkHasRegisterAsStaticReferenceMethod<T>(nullptr)) + sizeof(T); +}; + +template <typename T, bool = CanRegisterStaticLocalReference<T>::value> +class RegisterStaticLocalReference { + public: + static T* registerStatic(T* ptr) { return ptr; } +}; + +template <typename T> +class RegisterStaticLocalReference<T, true> { + public: + static T* registerStatic(T* ptr) { + return static_cast<T*>(ptr->registerAsStaticReference()); + } +}; + +#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) \ + WTF::RegisterStaticLocalReference<Type>::registerStatic(Object) +#else +#define WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE +#define LEAK_SANITIZER_IGNORE_OBJECT(X) ((void)0) +#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) Object +#endif // defined(LEAK_SANITIZER) + +} // namespace WTF + +#endif // WTF_LeakAnnotations_h
diff --git a/third_party/WebKit/Source/platform/wtf/Noncopyable.h b/third_party/WebKit/Source/platform/wtf/Noncopyable.h new file mode 100644 index 0000000..dade16e --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/Noncopyable.h
@@ -0,0 +1,29 @@ +/* + * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef WTF_Noncopyable_h +#define WTF_Noncopyable_h + +#define WTF_MAKE_NONCOPYABLE(ClassName) \ + private: \ + ClassName(const ClassName&) = delete; \ + ClassName& operator=(const ClassName&) = delete + +#endif // WTF_Noncopyable_h
diff --git a/third_party/WebKit/Source/platform/wtf/TypeTraits.h b/third_party/WebKit/Source/platform/wtf/TypeTraits.h new file mode 100644 index 0000000..ad0c60b --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/TypeTraits.h
@@ -0,0 +1,383 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TypeTraits_h +#define TypeTraits_h + +#include <cstddef> +#include <type_traits> +#include <utility> + +#include "platform/wtf/Compiler.h" + +namespace WTF { + +// Returns a string that contains the type name of |T| as a substring. +template <typename T> +inline const char* getStringWithTypeName() { + return WTF_PRETTY_FUNCTION; +} + +template <typename T> +struct IsWeak { + static const bool value = false; +}; + +enum WeakHandlingFlag { + NoWeakHandlingInCollections, + WeakHandlingInCollections +}; + +template <typename T, typename From> +class IsAssignable { + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename T2, + typename From2, + typename = decltype(std::declval<T2&>() = std::declval<From2>())> + static YesType checkAssignability(int); + template <typename T2, typename From2> + static NoType checkAssignability(...); + + public: + static const bool value = + sizeof(checkAssignability<T, From>(0)) == sizeof(YesType); +}; + +template <typename T> +struct IsCopyAssignable { + static_assert(!std::is_reference<T>::value, "T must not be a reference."); + static const bool value = IsAssignable<T, const T&>::value; +}; + +template <typename T> +struct IsMoveAssignable { + static_assert(!std::is_reference<T>::value, "T must not be a reference."); + static const bool value = IsAssignable<T, T&&>::value; +}; + +template <typename T> +struct IsTriviallyCopyAssignable { + static const bool value = + __has_trivial_assign(T) && IsCopyAssignable<T>::value; +}; + +template <typename T> +struct IsTriviallyMoveAssignable { + // TODO(yutak): This isn't really correct, because __has_trivial_assign + // appears to look only at copy assignment. However, + // std::is_trivially_move_assignable isn't available at this moment, and + // there isn't a good way to write that ourselves. + // + // Here we use IsTriviallyCopyAssignable as a conservative approximation: if T + // is trivially copy assignable, T is trivially move assignable, too. This + // definition misses a case where T is trivially move-only assignable, but + // such cases should be rare. + static const bool value = IsTriviallyCopyAssignable<T>::value; +}; + +template <typename T> +class IsDestructible { + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename T2, typename = decltype(std::declval<T2>().~T2())> + static YesType checkDestructibility(int); + template <typename T2> + static NoType checkDestructibility(...); + + public: + static const bool value = + sizeof(checkDestructibility<T>(0)) == sizeof(YesType); +}; + +template <typename T> +struct IsTriviallyDefaultConstructible { + static const bool value = + __has_trivial_constructor(T) && std::is_constructible<T>::value; +}; + +template <typename T> +struct IsTriviallyDestructible { + static const bool value = + __has_trivial_destructor(T) && IsDestructible<T>::value; +}; + +template <typename T, typename U> +struct IsSubclass { + private: + typedef char YesType; + struct NoType { + char padding[8]; + }; + + static YesType subclassCheck(U*); + static NoType subclassCheck(...); + static T* t; + + public: + static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); +}; + +template <typename T, template <typename... V> class U> +struct IsSubclassOfTemplate { + private: + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename... W> + static YesType subclassCheck(U<W...>*); + static NoType subclassCheck(...); + static T* t; + + public: + static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); +}; + +template <typename T, template <typename V, size_t W> class U> +struct IsSubclassOfTemplateTypenameSize { + private: + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename X, size_t Y> + static YesType subclassCheck(U<X, Y>*); + static NoType subclassCheck(...); + static T* t; + + public: + static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); +}; + +template <typename T, template <typename V, size_t W, typename X> class U> +struct IsSubclassOfTemplateTypenameSizeTypename { + private: + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename Y, size_t Z, typename A> + static YesType subclassCheck(U<Y, Z, A>*); + static NoType subclassCheck(...); + static T* t; + + public: + static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); +}; + +template <typename T, template <class V> class OuterTemplate> +struct RemoveTemplate { + typedef T Type; +}; + +template <typename T, template <class V> class OuterTemplate> +struct RemoveTemplate<OuterTemplate<T>, OuterTemplate> { + typedef T Type; +}; + +#if (COMPILER(MSVC) || !GCC_VERSION_AT_LEAST(4, 9, 0)) && !COMPILER(CLANG) +// FIXME: MSVC bug workaround. Remove once MSVC STL is fixed. +// FIXME: GCC before 4.9.0 seems to have the same issue. +// C++ 2011 Spec (ISO/IEC 14882:2011(E)) 20.9.6.2 Table 51 states that +// the template parameters shall be a complete type if they are different types. +// However, MSVC checks for type completeness even if they are the same type. +// Here, we use a template specialization for same type case to allow incomplete +// types. + +template <typename T, typename U> +struct IsConvertible { + static const bool value = std::is_convertible<T, U>::value; +}; + +template <typename T> +struct IsConvertible<T, T> { + static const bool value = true; +}; + +#define EnsurePtrConvertibleArgDecl(From, To) \ + typename std::enable_if<WTF::IsConvertible<From*, To*>::value>::type* = \ + nullptr +#define EnsurePtrConvertibleArgDefn(From, To) \ + typename std::enable_if<WTF::IsConvertible<From*, To*>::value>::type* +#else +#define EnsurePtrConvertibleArgDecl(From, To) \ + typename std::enable_if<std::is_convertible<From*, To*>::value>::type* = \ + nullptr +#define EnsurePtrConvertibleArgDefn(From, To) \ + typename std::enable_if<std::is_convertible<From*, To*>::value>::type* +#endif + +} // namespace WTF + +namespace blink { + +class Visitor; + +} // namespace blink + +namespace WTF { + +template <typename T> +class IsTraceable { + typedef char YesType; + typedef struct NoType { char padding[8]; } NoType; + + // Note that this also checks if a superclass of V has a trace method. + template <typename V> + static YesType checkHasTraceMethod( + V* v, + blink::Visitor* p = nullptr, + typename std::enable_if< + std::is_same<decltype(v->trace(p)), void>::value>::type* g = nullptr); + template <typename V> + static NoType checkHasTraceMethod(...); + + public: + // We add sizeof(T) to both sides here, because we want it to fail for + // incomplete types. Otherwise it just assumes that incomplete types do not + // have a trace method, which may not be true. + static const bool value = sizeof(YesType) + sizeof(T) == + sizeof(checkHasTraceMethod<T>(nullptr)) + sizeof(T); +}; + +// Convenience template wrapping the IsTraceableInCollection template in +// Collection Traits. It helps make the code more readable. +template <typename Traits> +class IsTraceableInCollectionTrait { + public: + static const bool value = Traits::template IsTraceableInCollection<>::value; +}; + +template <typename T, typename U> +struct IsTraceable<std::pair<T, U>> { + static const bool value = IsTraceable<T>::value || IsTraceable<U>::value; +}; + +// This is used to check that DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects are not +// stored in off-heap Vectors, HashTables etc. +template <typename T> +struct AllowsOnlyPlacementNew { + private: + using YesType = char; + struct NoType { + char padding[8]; + }; + + template <typename U> + static YesType checkMarker(typename U::IsAllowOnlyPlacementNew*); + template <typename U> + static NoType checkMarker(...); + + public: + static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType); +}; + +template <typename T> +class IsGarbageCollectedType { + typedef char YesType; + typedef struct NoType { char padding[8]; } NoType; + + static_assert(sizeof(T), "T must be fully defined"); + + using NonConstType = typename std::remove_const<T>::type; + template <typename U> + static YesType checkGarbageCollectedType( + typename U::IsGarbageCollectedTypeMarker*); + template <typename U> + static NoType checkGarbageCollectedType(...); + + // Separately check for GarbageCollectedMixin, which declares a different + // marker typedef, to avoid resolution ambiguity for cases like + // IsGarbageCollectedType<B> over: + // + // class A : public GarbageCollected<A>, public GarbageCollectedMixin { + // USING_GARBAGE_COLLECTED_MIXIN(A); + // ... + // }; + // class B : public A, public GarbageCollectedMixin { ... }; + // + template <typename U> + static YesType checkGarbageCollectedMixinType( + typename U::IsGarbageCollectedMixinMarker*); + template <typename U> + static NoType checkGarbageCollectedMixinType(...); + + public: + static const bool value = + (sizeof(YesType) == + sizeof(checkGarbageCollectedType<NonConstType>(nullptr))) || + (sizeof(YesType) == + sizeof(checkGarbageCollectedMixinType<NonConstType>(nullptr))); +}; + +template <> +class IsGarbageCollectedType<void> { + public: + static const bool value = false; +}; + +template <typename T> +class IsPersistentReferenceType { + typedef char YesType; + typedef struct NoType { char padding[8]; } NoType; + + template <typename U> + static YesType checkPersistentReferenceType( + typename U::IsPersistentReferenceTypeMarker*); + template <typename U> + static NoType checkPersistentReferenceType(...); + + public: + static const bool value = + (sizeof(YesType) == sizeof(checkPersistentReferenceType<T>(nullptr))); +}; + +template <typename T, + bool = std::is_function<typename std::remove_const< + typename std::remove_pointer<T>::type>::type>::value || + std::is_void<typename std::remove_const< + typename std::remove_pointer<T>::type>::type>::value> +class IsPointerToGarbageCollectedType { + public: + static const bool value = false; +}; + +template <typename T> +class IsPointerToGarbageCollectedType<T*, false> { + public: + static const bool value = IsGarbageCollectedType<T>::value; +}; + +} // namespace WTF + +using WTF::IsGarbageCollectedType; + +#endif // TypeTraits_h
diff --git a/third_party/WebKit/Source/platform/wtf/build_config.h b/third_party/WebKit/Source/platform/wtf/build_config.h new file mode 100644 index 0000000..57d89fd8 --- /dev/null +++ b/third_party/WebKit/Source/platform/wtf/build_config.h
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2013 Apple Inc. + * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef WTF_build_config_h +#define WTF_build_config_h + +#include "build/build_config.h" +#include "platform/wtf/Compiler.h" + +/* ==== Platform adaptation macros: these describe properties of the target + * environment. ==== */ + +/* HAVE() - specific system features (headers, functions or similar) that are + * present or not */ +#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE) +/* OS() - underlying operating system; only to be used for mandated low-level + services like + virtual memory, not to choose a GUI toolkit */ +#define OS(WTF_FEATURE) (defined OS_##WTF_FEATURE && OS_##WTF_FEATURE) + +/* ==== Policy decision macros: these define policy choices for a particular + * port. ==== */ + +/* USE() - use a particular third-party library or optional OS service */ +#define USE(WTF_FEATURE) \ + (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE) +/* ENABLE() - turn on a specific feature of WebKit */ +#define ENABLE(WTF_FEATURE) \ + (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE) + +/* There is an assumption in the project that either OS(WIN) or OS(POSIX) is + * set. */ +#if !OS(WIN) && !OS(POSIX) +#error Either OS(WIN) or OS(POSIX) needs to be set. +#endif + +#endif // WTF_build_config_h
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp index 0d92d85..bf4efd0 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -929,7 +929,6 @@ frameElement->scrollingMode(), frameElement->marginWidth(), frameElement->marginHeight(), frameElement->allowFullscreen(), frameElement->allowPaymentRequest(), frameElement->csp(), - frameElement->delegatedPermissions(), frameElement->allowedFeatures())); }
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp index 9d4a06a0..5d277c2 100644 --- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp +++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -316,7 +316,7 @@ PagePopupClient::addString("style: {\n", data); if (style->visibility() == EVisibility::kHidden) addProperty("visibility", String("hidden"), data); - if (style->display() == EDisplay::None) + if (style->display() == EDisplay::kNone) addProperty("display", String("none"), data); const ComputedStyle& baseStyle = context.baseStyle(); if (baseStyle.direction() != style->direction()) {
diff --git a/third_party/WebKit/Source/web/RemoteFrameOwner.h b/third_party/WebKit/Source/web/RemoteFrameOwner.h index 428f5b8..8d432b9 100644 --- a/third_party/WebKit/Source/web/RemoteFrameOwner.h +++ b/third_party/WebKit/Source/web/RemoteFrameOwner.h
@@ -48,10 +48,6 @@ bool allowFullscreen() const override { return m_allowFullscreen; } bool allowPaymentRequest() const override { return m_allowPaymentRequest; } AtomicString csp() const override { return m_csp; } - const WebVector<mojom::blink::PermissionName>& delegatedPermissions() - const override { - return m_delegatedPermissions; - } const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override { return m_allowedFeatures; } @@ -69,10 +65,6 @@ m_allowPaymentRequest = allowPaymentRequest; } void setCsp(const WebString& csp) { m_csp = csp; } - void setDelegatedpermissions( - const WebVector<mojom::blink::PermissionName>& delegatedPermissions) { - m_delegatedPermissions = delegatedPermissions; - } void setAllowedFeatures( const WebVector<WebFeaturePolicyFeature>& allowedFeatures) { m_allowedFeatures = allowedFeatures; @@ -97,7 +89,6 @@ bool m_allowFullscreen; bool m_allowPaymentRequest; WebString m_csp; - WebVector<mojom::blink::PermissionName> m_delegatedPermissions; WebVector<WebFeaturePolicyFeature> m_allowedFeatures; };
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp index e68acb7..e50ce42be 100644 --- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp +++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -374,7 +374,7 @@ m_session->append(pageAgent); m_session->append(new InspectorLogAgent( - &m_inspectedFrames->root()->host()->consoleMessageStorage(), + &m_inspectedFrames->root()->page()->consoleMessageStorage(), m_inspectedFrames->root()->performanceMonitor())); m_session->append(
diff --git a/third_party/WebKit/Source/web/WebFrame.cpp b/third_party/WebKit/Source/web/WebFrame.cpp index 02182db..099be8f5 100644 --- a/third_party/WebKit/Source/web/WebFrame.cpp +++ b/third_party/WebKit/Source/web/WebFrame.cpp
@@ -164,7 +164,6 @@ owner->setAllowFullscreen(properties.allowFullscreen); owner->setAllowPaymentRequest(properties.allowPaymentRequest); owner->setCsp(properties.requiredCsp); - owner->setDelegatedpermissions(properties.delegatedPermissions); owner->setAllowedFeatures(properties.allowedFeatures); }
diff --git a/third_party/WebKit/Source/web/WebInputMethodControllerImpl.cpp b/third_party/WebKit/Source/web/WebInputMethodControllerImpl.cpp index e71d80d..7b491d2 100644 --- a/third_party/WebKit/Source/web/WebInputMethodControllerImpl.cpp +++ b/third_party/WebKit/Source/web/WebInputMethodControllerImpl.cpp
@@ -50,8 +50,8 @@ int selectionStart, int selectionEnd) { if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) { - return plugin->setComposition(text, underlines, selectionStart, - selectionEnd); + return plugin->setComposition(text, underlines, replacementRange, + selectionStart, selectionEnd); } // We should use this |editor| object only to complete the ongoing @@ -128,8 +128,10 @@ UserGestureIndicator gestureIndicator(DocumentUserGestureToken::create( frame()->document(), UserGestureToken::NewGesture)); - if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) - return plugin->commitText(text, underlines, relativeCaretPosition); + if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) { + return plugin->commitText(text, underlines, replacementRange, + relativeCaretPosition); + } // Select the range to be replaced with the composition later. if (!replacementRange.isNull())
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index 01a75f3..34a3e9c3 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1638,7 +1638,7 @@ ownerElement->scrollingMode(), ownerElement->marginWidth(), ownerElement->marginHeight(), ownerElement->allowFullscreen(), ownerElement->allowPaymentRequest(), ownerElement->csp(), - ownerElement->delegatedPermissions(), ownerElement->allowedFeatures()); + ownerElement->allowedFeatures()); // FIXME: Using subResourceAttributeName as fallback is not a perfect // solution. subResourceAttributeName returns just one attribute name. The // element might not have the attribute, and there might be other attributes
diff --git a/third_party/WebKit/Source/wtf/AddressSanitizer.h b/third_party/WebKit/Source/wtf/AddressSanitizer.h index 07b9934..812da44 100644 --- a/third_party/WebKit/Source/wtf/AddressSanitizer.h +++ b/third_party/WebKit/Source/wtf/AddressSanitizer.h
@@ -1,42 +1,9 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WTF_AddressSanitizer_h -#define WTF_AddressSanitizer_h -// TODO(kojii): This file will need to be renamed, because it's no more -// specific to AddressSanitizer. +#include "platform/wtf/AddressSanitizer.h" -#include "wtf/build_config.h" - -// TODO(sof): Add SyZyASan support? -#if defined(ADDRESS_SANITIZER) -#include <sanitizer/asan_interface.h> -#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) -#else -#define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) -#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size)) -#define NO_SANITIZE_ADDRESS -#endif - -#if defined(LEAK_SANITIZER) -#include <sanitizer/lsan_interface.h> -#else -#define __lsan_register_root_region(addr, size) ((void)(addr), (void)(size)) -#define __lsan_unregister_root_region(addr, size) ((void)(addr), (void)(size)) -#endif - -#if defined(MEMORY_SANITIZER) -#include <sanitizer/msan_interface.h> -#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) -#else -#define NO_SANITIZE_MEMORY -#endif - -#if defined(THREAD_SANITIZER) -#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) -#else -#define NO_SANITIZE_THREAD -#endif - -#endif // WTF_AddressSanitizer_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Alignment.h b/third_party/WebKit/Source/wtf/Alignment.h index c2ea860..a6f8295f 100644 --- a/third_party/WebKit/Source/wtf/Alignment.h +++ b/third_party/WebKit/Source/wtf/Alignment.h
@@ -1,94 +1,9 @@ -/* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_Alignment_h -#define WTF_Alignment_h +#include "platform/wtf/Alignment.h" -#include "wtf/Compiler.h" -#include <algorithm> -#include <stdint.h> -#include <utility> - -namespace WTF { - -#if COMPILER(GCC) -#define WTF_ALIGN_OF(type) __alignof__(type) -#define WTF_ALIGNED(variable_type, variable, n) \ - variable_type variable __attribute__((__aligned__(n))) -#elif COMPILER(MSVC) -#define WTF_ALIGN_OF(type) __alignof(type) -#define WTF_ALIGNED(variable_type, variable, n) \ - __declspec(align(n)) variable_type variable -#else -#error WTF_ALIGN macros need alignment control. -#endif - -#if COMPILER(GCC) -typedef char __attribute__((__may_alias__)) AlignedBufferChar; -#else -typedef char AlignedBufferChar; -#endif - -template <size_t size, size_t alignment> -struct AlignedBuffer; -template <size_t size> -struct AlignedBuffer<size, 1> { - AlignedBufferChar buffer[size]; -}; -template <size_t size> -struct AlignedBuffer<size, 2> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 2); -}; -template <size_t size> -struct AlignedBuffer<size, 4> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 4); -}; -template <size_t size> -struct AlignedBuffer<size, 8> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 8); -}; -template <size_t size> -struct AlignedBuffer<size, 16> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 16); -}; -template <size_t size> -struct AlignedBuffer<size, 32> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 32); -}; -template <size_t size> -struct AlignedBuffer<size, 64> { - WTF_ALIGNED(AlignedBufferChar, buffer[size], 64); -}; - -template <size_t size, size_t alignment> -void swap(AlignedBuffer<size, alignment>& a, - AlignedBuffer<size, alignment>& b) { - for (size_t i = 0; i < size; ++i) - std::swap(a.buffer[i], b.buffer[i]); -} - -template <uintptr_t mask> -inline bool isAlignedTo(const void* pointer) { - return !(reinterpret_cast<uintptr_t>(pointer) & mask); -} - -} // namespace WTF - -#endif // WTF_Alignment_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/AutoReset.h b/third_party/WebKit/Source/wtf/AutoReset.h index b74eaf8..9af14ce 100644 --- a/third_party/WebKit/Source/wtf/AutoReset.h +++ b/third_party/WebKit/Source/wtf/AutoReset.h
@@ -1,42 +1,9 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef AutoReset_h -#define AutoReset_h +#include "platform/wtf/AutoReset.h" -#include "base/auto_reset.h" - -namespace WTF { - -// WTF::AutoReset is base::AutoReset. See base/auto_reset.h for documentation. - -template <typename T> -using AutoReset = base::AutoReset<T>; - -} // namespace WTF - -using WTF::AutoReset; - -#endif +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/BUILD.gn b/third_party/WebKit/Source/wtf/BUILD.gn index 44973f2..7878ea1 100644 --- a/third_party/WebKit/Source/wtf/BUILD.gn +++ b/third_party/WebKit/Source/wtf/BUILD.gn
@@ -39,7 +39,6 @@ "ConditionalDestructor.h", "ContainerAnnotations.h", "CryptographicallyRandomNumber.h", - "CurrentTime.cpp", "CurrentTime.h", "DataLog.cpp", "DataLog.h", @@ -47,7 +46,6 @@ "DateMath.h", "Deque.h", "DoublyLinkedList.h", - "DynamicAnnotations.cpp", "DynamicAnnotations.h", "FilePrintStream.cpp", "FilePrintStream.h",
diff --git a/third_party/WebKit/Source/wtf/BitwiseOperations.h b/third_party/WebKit/Source/wtf/BitwiseOperations.h index e07227a..9e313a571 100644 --- a/third_party/WebKit/Source/wtf/BitwiseOperations.h +++ b/third_party/WebKit/Source/wtf/BitwiseOperations.h
@@ -1,52 +1,9 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -// TODO(palmer): The only caller of this code in Blink is PartitionAlloc. When -// PA is moved to base, we can remove this file. -// https://bugs.chromium.org/p/chromium/issues/detail?id=632441 +#include "platform/wtf/WTFExport.h" -#ifndef WTF_BitwiseOperations_h -#define WTF_BitwiseOperations_h - -#include "base/bits.h" -#include "wtf/CPU.h" - -namespace WTF { - -using base::bits::CountLeadingZeroBits32; -using base::bits::CountLeadingZeroBitsSizeT; - -#if CPU(64BIT) -using base::bits::CountLeadingZeroBits64; -#endif - -} // namespace WTF - -#endif // WTF_BitwiseOperations_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ByteSwap.h b/third_party/WebKit/Source/wtf/ByteSwap.h index 3f4462c..21a7fe7 100644 --- a/third_party/WebKit/Source/wtf/ByteSwap.h +++ b/third_party/WebKit/Source/wtf/ByteSwap.h
@@ -1,91 +1,9 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_ByteSwap_h -#define WTF_ByteSwap_h +#include "platform/wtf/ByteSwap.h" -#include "wtf/CPU.h" -#include "wtf/Compiler.h" - -#include <stdint.h> - -#if COMPILER(MSVC) -#include <stdlib.h> -#endif - -namespace WTF { - -inline uint32_t wswap32(uint32_t x) { - return ((x & 0xffff0000) >> 16) | ((x & 0x0000ffff) << 16); -} - -#if COMPILER(MSVC) - -ALWAYS_INLINE uint64_t bswap64(uint64_t x) { - return _byteswap_uint64(x); -} -ALWAYS_INLINE uint32_t bswap32(uint32_t x) { - return _byteswap_ulong(x); -} -ALWAYS_INLINE uint16_t bswap16(uint16_t x) { - return _byteswap_ushort(x); -} - -#else - -ALWAYS_INLINE uint64_t bswap64(uint64_t x) { - return __builtin_bswap64(x); -} -ALWAYS_INLINE uint32_t bswap32(uint32_t x) { - return __builtin_bswap32(x); -} -ALWAYS_INLINE uint16_t bswap16(uint16_t x) { - return __builtin_bswap16(x); -} - -#endif - -#if CPU(64BIT) - -ALWAYS_INLINE size_t bswapuintptrt(size_t x) { - return bswap64(x); -} - -#else - -ALWAYS_INLINE size_t bswapuintptrt(size_t x) { - return bswap32(x); -} - -#endif - -} // namespace WTF - -#endif // WTF_ByteSwap_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/CPU.h b/third_party/WebKit/Source/wtf/CPU.h index daedf8e..b617339 100644 --- a/third_party/WebKit/Source/wtf/CPU.h +++ b/third_party/WebKit/Source/wtf/CPU.h
@@ -1,171 +1,9 @@ -/* - * Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2007-2009 Torch Mobile, Inc. - * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. - * Copyright (C) 2013 Samsung Electronics. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_CPU_h -#define WTF_CPU_h +#include "platform/wtf/CPU.h" -#include "wtf/Compiler.h" - -/* CPU() - the target CPU architecture */ -#define CPU(WTF_FEATURE) \ - (defined WTF_CPU_##WTF_FEATURE && WTF_CPU_##WTF_FEATURE) - -/* ==== CPU() - the target CPU architecture ==== */ - -/* This defines CPU(BIG_ENDIAN) or nothing, as appropriate. */ -/* This defines CPU(32BIT) or CPU(64BIT), as appropriate. */ - -/* CPU(X86) - i386 / x86 32-bit */ -#if defined(__i386__) || defined(i386) || defined(_M_IX86) || \ - defined(_X86_) || defined(__THW_INTEL) -#define WTF_CPU_X86 1 -#endif - -/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */ -#if defined(__x86_64__) || defined(_M_X64) -#define WTF_CPU_X86_64 1 -#define WTF_CPU_64BIT 1 -#endif - -/* CPU(ARM) - ARM, any version*/ -#define WTF_ARM_ARCH_AT_LEAST(N) \ - (CPU(ARM) && defined(WTF_ARM_ARCH_VERSION) && WTF_ARM_ARCH_VERSION >= N) - -#if defined(arm) || defined(__arm__) || defined(ARM) || defined(_ARM_) -#define WTF_CPU_ARM 1 - -#if defined(__ARMEB__) -#define WTF_CPU_BIG_ENDIAN 1 - -#elif !defined(__ARM_EABI__) && !defined(__EABI__) && !defined(__VFP_FP__) && \ - !defined(_WIN32_WCE) && !defined(ANDROID) -#define WTF_CPU_MIDDLE_ENDIAN 1 - -#endif - -/* Set WTF_ARM_ARCH_VERSION */ -#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ - defined(__MARM_ARMV4__) -#define WTF_ARM_ARCH_VERSION 4 - -#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ - defined(__MARM_ARMV5__) -#define WTF_ARM_ARCH_VERSION 5 - -#elif defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \ - defined(__ARM_ARCH_5TEJ__) -#define WTF_ARM_ARCH_VERSION 5 - -#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ - defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ - defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \ - defined(__ARMV6__) -#define WTF_ARM_ARCH_VERSION 6 - -#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ - defined(__ARM_ARCH_7S__) -#define WTF_ARM_ARCH_VERSION 7 - -/* MSVC sets _M_ARM */ -#elif defined(_M_ARM) -#define WTF_ARM_ARCH_VERSION _M_ARM -#else -#define WTF_ARM_ARCH_VERSION 0 - -#endif - -/* Set WTF_THUMB_ARCH_VERSION */ -#if defined(__ARM_ARCH_4T__) -#define WTF_THUMB_ARCH_VERSION 1 - -#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) || \ - defined(__ARM_ARCH_5TEJ__) -#define WTF_THUMB_ARCH_VERSION 2 - -#elif defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || \ - defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || \ - defined(__ARM_ARCH_6M__) -#define WTF_THUMB_ARCH_VERSION 3 - -#elif defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_7__) || \ - defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7M__) || \ - defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7S__) -#define WTF_THUMB_ARCH_VERSION 4 - -#else -#define WTF_THUMB_ARCH_VERSION 0 -#endif - -/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */ -#if !defined(WTF_CPU_ARM_THUMB2) -#if defined(thumb2) || defined(__thumb2__) || \ - ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) -#define WTF_CPU_ARM_THUMB2 1 -#elif WTF_ARM_ARCH_AT_LEAST(4) -#define WTF_CPU_ARM_THUMB2 0 -#else -#error "Unsupported ARM architecture" -#endif -#endif /* !defined(WTF_CPU_ARM_THUMB2) */ - -#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON) -#define WTF_CPU_ARM_NEON 1 -#endif - -#if CPU(ARM_NEON) && \ - (COMPILER(CLANG) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4, 7, 0)) -// All NEON intrinsics usage can be disabled by this macro. -#define HAVE_ARM_NEON_INTRINSICS 1 -#endif - -#endif /* ARM */ - -/* CPU(ARM64) - AArch64 64-bit */ -#if defined(__aarch64__) -#define WTF_CPU_ARM64 1 -#define WTF_CPU_64BIT 1 -#endif - -/* CPU(MIPS), CPU(MIPS64) */ -#if defined(__mips__) && (__mips == 64) -#define WTF_CPU_MIPS64 1 -#define WTF_CPU_64BIT 1 -#elif defined(__mips__) -#define WTF_CPU_MIPS 1 -#endif - -#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) -// All MSA intrinsics usage can be disabled by this macro. -#define HAVE_MIPS_MSA_INTRINSICS 1 -#endif - -#if !defined(WTF_CPU_64BIT) -#define WTF_CPU_32BIT 1 -#endif - -#endif /* WTF_CPU_h */ +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/CheckedNumeric.h b/third_party/WebKit/Source/wtf/CheckedNumeric.h index f94ba48..4fe900f8 100644 --- a/third_party/WebKit/Source/wtf/CheckedNumeric.h +++ b/third_party/WebKit/Source/wtf/CheckedNumeric.h
@@ -1,39 +1,9 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_CheckedNumeric_h -#define WTF_CheckedNumeric_h +#include "platform/wtf/CheckedNumeric.h" -/* See base/numerics/safe_math.h for usage. - */ -#include "base/numerics/safe_math.h" - -namespace WTF { -using base::CheckedNumeric; -} // namespace WTF - -using WTF::CheckedNumeric; - -#endif +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Compiler.h b/third_party/WebKit/Source/wtf/Compiler.h index 1b81bb9..a554dcd1 100644 --- a/third_party/WebKit/Source/wtf/Compiler.h +++ b/third_party/WebKit/Source/wtf/Compiler.h
@@ -1,100 +1,9 @@ -/* - * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_Compiler_h -#define WTF_Compiler_h +#include "platform/wtf/Compiler.h" -#include "base/compiler_specific.h" - -/* COMPILER() - the compiler being used to build the project */ -#define COMPILER(WTF_FEATURE) \ - (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE) - -/* ==== COMPILER() - the compiler being used to build the project ==== */ - -/* COMPILER(CLANG) - Clang */ -#if defined(__clang__) -#define WTF_COMPILER_CLANG 1 -#endif - -/* COMPILER(MSVC) - Microsoft Visual C++ (and Clang when compiling for Windows). - */ -#if defined(_MSC_VER) -#define WTF_COMPILER_MSVC 1 -#endif - -/* COMPILER(GCC) - GNU Compiler Collection (and Clang when compiling for - * platforms other than Windows). */ -#if defined(__GNUC__) -#define WTF_COMPILER_GCC 1 -#define GCC_VERSION \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#define GCC_VERSION_AT_LEAST(major, minor, patch) \ - (GCC_VERSION >= (major * 10000 + minor * 100 + patch)) -#else -/* Define this for !GCC compilers, just so we can write things like - * GCC_VERSION_AT_LEAST(4, 1, 0). */ -#define GCC_VERSION_AT_LEAST(major, minor, patch) 0 -#endif - -/* ==== Compiler features ==== */ - -/* NEVER_INLINE */ - -// TODO(palmer): Remove this and update callers to use NOINLINE from Chromium -// base. https://bugs.chromium.org/p/chromium/issues/detail?id=632441 -#define NEVER_INLINE NOINLINE - -/* OBJC_CLASS */ - -#ifndef OBJC_CLASS -#ifdef __OBJC__ -#define OBJC_CLASS @class -#else -#define OBJC_CLASS class -#endif -#endif - -/* WTF_PRETTY_FUNCTION */ - -#if COMPILER(GCC) -#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#elif COMPILER(MSVC) -#define WTF_PRETTY_FUNCTION __FUNCSIG__ -#else -#define WTF_PRETTY_FUNCTION __func__ -#endif - -/* NO_SANITIZE_UNRELATED_CAST - Disable runtime checks related to casts between - * unrelated objects (-fsanitize=cfi-unrelated-cast or -fsanitize=vptr). */ - -#if COMPILER(CLANG) -#define NO_SANITIZE_UNRELATED_CAST \ - __attribute__((no_sanitize("cfi-unrelated-cast", "vptr"))) -#else -#define NO_SANITIZE_UNRELATED_CAST -#endif - -#endif /* WTF_Compiler_h */ +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ConditionalDestructor.h b/third_party/WebKit/Source/wtf/ConditionalDestructor.h index c2fdd1c5..fc4ba2a4 100644 --- a/third_party/WebKit/Source/wtf/ConditionalDestructor.h +++ b/third_party/WebKit/Source/wtf/ConditionalDestructor.h
@@ -1,28 +1,9 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ConditionalDestructor_h -#define ConditionalDestructor_h +#include "platform/wtf/ConditionalDestructor.h" -namespace WTF { - -// ConditionalDestructor defines the destructor of the derived object. -// This base is used in order to completely avoid creating a destructor -// for an object that does not need to be destructed. By doing so, -// the clang compiler will have correct information about whether or not -// the object has a trivial destructor. -// Note: the derived object MUST release all its recources at the finalize() -// method. -template <typename Derived, bool noDestructor> -class ConditionalDestructor { - public: - ~ConditionalDestructor() { static_cast<Derived*>(this)->finalize(); } -}; - -template <typename Derived> -class ConditionalDestructor<Derived, true> {}; - -} // namespace WTF - -#endif // ConditionalDestructor_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ContainerAnnotations.h b/third_party/WebKit/Source/wtf/ContainerAnnotations.h index 401cc60..ff2a3cb 100644 --- a/third_party/WebKit/Source/wtf/ContainerAnnotations.h +++ b/third_party/WebKit/Source/wtf/ContainerAnnotations.h
@@ -1,44 +1,9 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WTF_ContainerAnnotations_h -#define WTF_ContainerAnnotations_h +#include "platform/wtf/ContainerAnnotations.h" -#include "wtf/AddressSanitizer.h" -#include "wtf/CPU.h" - -// TODO(ochang): Remove the CPU(X86_64) condition to enable this for X86 once -// the crashes there have been fixed: http://crbug.com/461406 -#if defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) -#define ANNOTATE_CONTIGUOUS_CONTAINER -#define ANNOTATE_NEW_BUFFER(buffer, capacity, newSize) \ - if (buffer) { \ - __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ - (buffer) + (capacity), \ - (buffer) + (newSize)); \ - } -#define ANNOTATE_DELETE_BUFFER(buffer, capacity, oldSize) \ - if (buffer) { \ - __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ - (buffer) + (oldSize), \ - (buffer) + (capacity)); \ - } -#define ANNOTATE_CHANGE_SIZE(buffer, capacity, oldSize, newSize) \ - if (buffer) { \ - __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \ - (buffer) + (oldSize), \ - (buffer) + (newSize)); \ - } -#define ANNOTATE_CHANGE_CAPACITY(buffer, oldCapacity, bufferSize, newCapacity) \ - ANNOTATE_DELETE_BUFFER(buffer, oldCapacity, bufferSize); \ - ANNOTATE_NEW_BUFFER(buffer, newCapacity, bufferSize); -// Annotations require buffers to begin on an 8-byte boundary. -#else // defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) -#define ANNOTATE_NEW_BUFFER(buffer, capacity, newSize) -#define ANNOTATE_DELETE_BUFFER(buffer, capacity, oldSize) -#define ANNOTATE_CHANGE_SIZE(buffer, capacity, oldSize, newSize) -#define ANNOTATE_CHANGE_CAPACITY(buffer, oldCapacity, bufferSize, newCapacity) -#endif // defined(ADDRESS_SANITIZER) && OS(LINUX) && CPU(X86_64) - -#endif // WTF_ContainerAnnotations_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/CurrentTime.h b/third_party/WebKit/Source/wtf/CurrentTime.h index b1acf736..d57fec06 100644 --- a/third_party/WebKit/Source/wtf/CurrentTime.h +++ b/third_party/WebKit/Source/wtf/CurrentTime.h
@@ -1,79 +1,9 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2008 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef CurrentTime_h -#define CurrentTime_h +#include "platform/wtf/CurrentTime.h" -#include "wtf/WTFExport.h" - -namespace WTF { - -// Returns the current UTC time in seconds, counted from January 1, 1970. -// Precision varies depending on platform but is usually as good or better -// than a millisecond. -WTF_EXPORT double currentTime(); - -// Same thing, in milliseconds. -inline double currentTimeMS() { - return currentTime() * 1000.0; -} - -// Provides a monotonically increasing time in seconds since an arbitrary point -// in the past. On unsupported platforms, this function only guarantees the -// result will be non-decreasing. -WTF_EXPORT double monotonicallyIncreasingTime(); - -// Same thing, in milliseconds. -inline double monotonicallyIncreasingTimeMS() { - return monotonicallyIncreasingTime() * 1000.0; -} - -using TimeFunction = double (*)(); - -// Make all the time functions (currentTime(), monotonicallyIncreasingTime(), -// systemTraceTime()) return the result of the supplied function. Returns the -// pointer to the old time function. For both setting and getting, nullptr -// means using the default timing function returning the actual time. -WTF_EXPORT TimeFunction setTimeFunctionsForTesting(TimeFunction); - -// Allows wtf/Time.h to use the same mock time function -WTF_EXPORT TimeFunction getTimeFunctionForTesting(); - -} // namespace WTF - -using WTF::currentTime; -using WTF::currentTimeMS; -using WTF::monotonicallyIncreasingTime; -using WTF::monotonicallyIncreasingTimeMS; -using WTF::TimeFunction; -using WTF::setTimeFunctionsForTesting; - -#endif // CurrentTime_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/DynamicAnnotations.h b/third_party/WebKit/Source/wtf/DynamicAnnotations.h index 33e9cd3..a7fc401 100644 --- a/third_party/WebKit/Source/wtf/DynamicAnnotations.h +++ b/third_party/WebKit/Source/wtf/DynamicAnnotations.h
@@ -1,114 +1,9 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_DynamicAnnotations_h -#define WTF_DynamicAnnotations_h +#include "platform/wtf/DynamicAnnotations.h" -/* This file defines dynamic annotations for use with dynamic analysis - * tool such as ThreadSanitizer, Valgrind, etc. - * - * Dynamic annotation is a source code annotation that affects - * the generated code (that is, the annotation is not a comment). - * Each such annotation is attached to a particular - * instruction and/or to a particular object (address) in the program. - * - * By using dynamic annotations a developer can give more details to the dynamic - * analysis tool to improve its precision. - * - * In C/C++ program the annotations are represented as C macros. - * With the default build flags, these macros are empty, hence don't affect - * performance of a compiled binary. - * If dynamic annotations are enabled, they just call no-op functions. - * The dynamic analysis tools can intercept these functions and replace them - * with their own implementations. - * - * See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations for more - * information. - */ - -#include "wtf/WTFExport.h" -#include "wtf/build_config.h" - -#if USE(DYNAMIC_ANNOTATIONS) -/* Tell data race detector that we're not interested in reports on the given - * address range. */ -#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - WTFAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) -#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) \ - WTFAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, sizeof(*(pointer)), \ - description) - -/* Annotations for user-defined synchronization mechanisms. - * These annotations can be used to define happens-before arcs in user-defined - * synchronization mechanisms: the race detector will infer an arc from - * the former to the latter when they share the same argument pointer. - * - * The most common case requiring annotations is atomic reference counting: - * bool deref() { - * ANNOTATE_HAPPENS_BEFORE(&m_refCount); - * if (!atomicDecrement(&m_refCount)) { - * // m_refCount is now 0 - * ANNOTATE_HAPPENS_AFTER(&m_refCount); - * // "return true; happens-after each atomicDecrement of m_refCount" - * return true; - * } - * return false; - * } - */ -#define WTF_ANNOTATE_HAPPENS_BEFORE(address) \ - WTFAnnotateHappensBefore(__FILE__, __LINE__, address) -#define WTF_ANNOTATE_HAPPENS_AFTER(address) \ - WTFAnnotateHappensAfter(__FILE__, __LINE__, address) - -#ifdef __cplusplus -extern "C" { -#endif -/* Don't use these directly, use the above macros instead. */ -WTF_EXPORT void WTFAnnotateBenignRaceSized(const char* file, - int line, - const volatile void* memory, - long size, - const char* description); -WTF_EXPORT void WTFAnnotateHappensBefore(const char* file, - int line, - const volatile void* address); -WTF_EXPORT void WTFAnnotateHappensAfter(const char* file, - int line, - const volatile void* address); -#ifdef __cplusplus -} // extern "C" -#endif - -#else // USE(DYNAMIC_ANNOTATIONS) -/* These macros are empty when dynamic annotations are not enabled so you can - * use them without affecting the performance of release binaries. */ -#define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) -#define WTF_ANNOTATE_BENIGN_RACE(pointer, description) -#define WTF_ANNOTATE_HAPPENS_BEFORE(address) -#define WTF_ANNOTATE_HAPPENS_AFTER(address) -#endif // USE(DYNAMIC_ANNOTATIONS) - -#endif // WTF_DynamicAnnotations_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Forward.h b/third_party/WebKit/Source/wtf/Forward.h index 4eee7d7..d9e42c4 100644 --- a/third_party/WebKit/Source/wtf/Forward.h +++ b/third_party/WebKit/Source/wtf/Forward.h
@@ -1,84 +1,9 @@ -/* - * Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_Forward_h -#define WTF_Forward_h +#include "platform/wtf/Forward.h" -#include "wtf/Compiler.h" -#include <stddef.h> - -namespace WTF { - -template <typename T> -class PassRefPtr; -template <typename T> -class RefPtr; -template <typename T> -class StringBuffer; -template <typename T, size_t inlineCapacity, typename Allocator> -class Vector; - -class ArrayBuffer; -class ArrayBufferView; -class ArrayPiece; -class AtomicString; -class CString; -class Float32Array; -class Float64Array; -class Int8Array; -class Int16Array; -class Int32Array; -class OrdinalNumber; -class String; -class StringBuilder; -class StringImpl; -class StringView; -class Uint8Array; -class Uint8ClampedArray; -class Uint16Array; -class Uint32Array; - -} // namespace WTF - -using WTF::PassRefPtr; -using WTF::RefPtr; -using WTF::Vector; - -using WTF::ArrayBuffer; -using WTF::ArrayBufferView; -using WTF::ArrayPiece; -using WTF::AtomicString; -using WTF::CString; -using WTF::Float32Array; -using WTF::Float64Array; -using WTF::Int8Array; -using WTF::Int16Array; -using WTF::Int32Array; -using WTF::String; -using WTF::StringBuffer; -using WTF::StringBuilder; -using WTF::StringImpl; -using WTF::StringView; -using WTF::Uint8Array; -using WTF::Uint8ClampedArray; -using WTF::Uint16Array; -using WTF::Uint32Array; - -#endif // WTF_Forward_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/GetPtr.h b/third_party/WebKit/Source/wtf/GetPtr.h index f211f20..fc06e5c 100644 --- a/third_party/WebKit/Source/wtf/GetPtr.h +++ b/third_party/WebKit/Source/wtf/GetPtr.h
@@ -1,38 +1,9 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_GetPtr_h -#define WTF_GetPtr_h +#include "platform/wtf/GetPtr.h" -namespace WTF { - -template <typename T> -inline T* getPtr(T* p) { - return p; -} - -template <typename T> -inline T* getPtr(T& p) { - return &p; -} - -} // namespace WTF - -#endif // WTF_GetPtr_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/LeakAnnotations.h b/third_party/WebKit/Source/wtf/LeakAnnotations.h index d218794..f43de27 100644 --- a/third_party/WebKit/Source/wtf/LeakAnnotations.h +++ b/third_party/WebKit/Source/wtf/LeakAnnotations.h
@@ -1,142 +1,9 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * Copyright (C) 2013 Samsung Electronics. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_LeakAnnotations_h -#define WTF_LeakAnnotations_h +#include "platform/wtf/LeakAnnotations.h" -// This file defines macros for working with LeakSanitizer, allowing memory -// and allocations to be registered as exempted from LSan consideration. - -#include "wtf/Noncopyable.h" -#if defined(LEAK_SANITIZER) -#include "wtf/AddressSanitizer.h" -#include "wtf/TypeTraits.h" -#endif - -namespace WTF { - -#if defined(LEAK_SANITIZER) -class LeakSanitizerDisabler { - WTF_MAKE_NONCOPYABLE(LeakSanitizerDisabler); - - public: - LeakSanitizerDisabler() { __lsan_disable(); } - - ~LeakSanitizerDisabler() { __lsan_enable(); } -}; - -// WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE: all allocations made in the -// current scope will be exempted from LSan consideration. Only to be -// used internal to wtf/, Blink should use LEAK_SANITIZER_DISABLED_SCOPE -// elsewhere. -// -// TODO(sof): once layering rules allow wtf/ to make use of the Oilpan -// infrastructure, remove this macro. -#define WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE \ - WTF::LeakSanitizerDisabler leakSanitizerDisabler; \ - static_cast<void>(0) - -// LEAK_SANITIZER_IGNORE_OBJECT(X): the heap object referenced by pointer X -// will be ignored by LSan. -// -// "Ignorance" means that LSan's reachability traversal is stopped short -// upon encountering an ignored memory chunk. Consequently, LSan will not -// scan an ignored memory chunk for live, reachable pointers. However, should -// those embedded pointers be reachable by some other path, they will be -// reported as leaking. -#define LEAK_SANITIZER_IGNORE_OBJECT(X) __lsan_ignore_object(X) - -// If the object pointed to by the static local is on the Oilpan heap, a strong -// Persistent<> is created to keep the pointed-to heap object alive. This makes -// both the Persistent<> and the heap object _reachable_ by LeakSanitizer's leak -// detection pass. We do not want these intentional leaks to be reported by -// LSan, hence the static local is registered with Oilpan -// (see RegisterStaticLocalReference<> below.) -// -// Upon Blink shutdown, all the registered statics are released and a final -// round of GCs are performed to sweep out their now-unreachable object graphs. -// The end result being a tidied heap that the LeakSanitizer can then scan to -// report real leaks. -// -// The CanRegisterStaticLocalReference<> and RegisterStaticLocalReference<> -// templates arrange for this -- for a class type T, a registerStatic() -// implementation is provided if "T* T::registerAsStaticReference(T*)" is a -// method on T (inherited or otherwise.) -// -// An empty, trivial registerStatic() method is provided for all other class -// types T. -template <typename T> -class CanRegisterStaticLocalReference { - typedef char YesType; - typedef struct NoType { char padding[8]; } NoType; - - // Check if class T has public method "T* registerAsStaticReference()". - template <typename V> - static YesType checkHasRegisterAsStaticReferenceMethod( - V* p, - typename std::enable_if<IsSubclass< - V, - typename std::remove_pointer<decltype( - p->registerAsStaticReference())>::type>::value>::type* = 0); - template <typename V> - static NoType checkHasRegisterAsStaticReferenceMethod(...); - - public: - static const bool value = - sizeof(YesType) + sizeof(T) == - sizeof(checkHasRegisterAsStaticReferenceMethod<T>(nullptr)) + sizeof(T); -}; - -template <typename T, bool = CanRegisterStaticLocalReference<T>::value> -class RegisterStaticLocalReference { - public: - static T* registerStatic(T* ptr) { return ptr; } -}; - -template <typename T> -class RegisterStaticLocalReference<T, true> { - public: - static T* registerStatic(T* ptr) { - return static_cast<T*>(ptr->registerAsStaticReference()); - } -}; - -#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) \ - WTF::RegisterStaticLocalReference<Type>::registerStatic(Object) -#else -#define WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE -#define LEAK_SANITIZER_IGNORE_OBJECT(X) ((void)0) -#define LEAK_SANITIZER_REGISTER_STATIC_LOCAL(Type, Object) Object -#endif // defined(LEAK_SANITIZER) - -} // namespace WTF - -#endif // WTF_LeakAnnotations_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Noncopyable.h b/third_party/WebKit/Source/wtf/Noncopyable.h index dade16e..e49a54b 100644 --- a/third_party/WebKit/Source/wtf/Noncopyable.h +++ b/third_party/WebKit/Source/wtf/Noncopyable.h
@@ -1,29 +1,9 @@ -/* - * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_Noncopyable_h -#define WTF_Noncopyable_h +#include "platform/wtf/Noncopyable.h" -#define WTF_MAKE_NONCOPYABLE(ClassName) \ - private: \ - ClassName(const ClassName&) = delete; \ - ClassName& operator=(const ClassName&) = delete - -#endif // WTF_Noncopyable_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/TypeTraits.h b/third_party/WebKit/Source/wtf/TypeTraits.h index 987d3d36..1fafd32a 100644 --- a/third_party/WebKit/Source/wtf/TypeTraits.h +++ b/third_party/WebKit/Source/wtf/TypeTraits.h
@@ -1,383 +1,9 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2009, 2010 Google Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef TypeTraits_h -#define TypeTraits_h +#include "platform/wtf/TypeTraits.h" -#include <cstddef> -#include <type_traits> -#include <utility> - -#include "wtf/Compiler.h" - -namespace WTF { - -// Returns a string that contains the type name of |T| as a substring. -template <typename T> -inline const char* getStringWithTypeName() { - return WTF_PRETTY_FUNCTION; -} - -template <typename T> -struct IsWeak { - static const bool value = false; -}; - -enum WeakHandlingFlag { - NoWeakHandlingInCollections, - WeakHandlingInCollections -}; - -template <typename T, typename From> -class IsAssignable { - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename T2, - typename From2, - typename = decltype(std::declval<T2&>() = std::declval<From2>())> - static YesType checkAssignability(int); - template <typename T2, typename From2> - static NoType checkAssignability(...); - - public: - static const bool value = - sizeof(checkAssignability<T, From>(0)) == sizeof(YesType); -}; - -template <typename T> -struct IsCopyAssignable { - static_assert(!std::is_reference<T>::value, "T must not be a reference."); - static const bool value = IsAssignable<T, const T&>::value; -}; - -template <typename T> -struct IsMoveAssignable { - static_assert(!std::is_reference<T>::value, "T must not be a reference."); - static const bool value = IsAssignable<T, T&&>::value; -}; - -template <typename T> -struct IsTriviallyCopyAssignable { - static const bool value = - __has_trivial_assign(T) && IsCopyAssignable<T>::value; -}; - -template <typename T> -struct IsTriviallyMoveAssignable { - // TODO(yutak): This isn't really correct, because __has_trivial_assign - // appears to look only at copy assignment. However, - // std::is_trivially_move_assignable isn't available at this moment, and - // there isn't a good way to write that ourselves. - // - // Here we use IsTriviallyCopyAssignable as a conservative approximation: if T - // is trivially copy assignable, T is trivially move assignable, too. This - // definition misses a case where T is trivially move-only assignable, but - // such cases should be rare. - static const bool value = IsTriviallyCopyAssignable<T>::value; -}; - -template <typename T> -class IsDestructible { - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename T2, typename = decltype(std::declval<T2>().~T2())> - static YesType checkDestructibility(int); - template <typename T2> - static NoType checkDestructibility(...); - - public: - static const bool value = - sizeof(checkDestructibility<T>(0)) == sizeof(YesType); -}; - -template <typename T> -struct IsTriviallyDefaultConstructible { - static const bool value = - __has_trivial_constructor(T) && std::is_constructible<T>::value; -}; - -template <typename T> -struct IsTriviallyDestructible { - static const bool value = - __has_trivial_destructor(T) && IsDestructible<T>::value; -}; - -template <typename T, typename U> -struct IsSubclass { - private: - typedef char YesType; - struct NoType { - char padding[8]; - }; - - static YesType subclassCheck(U*); - static NoType subclassCheck(...); - static T* t; - - public: - static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); -}; - -template <typename T, template <typename... V> class U> -struct IsSubclassOfTemplate { - private: - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename... W> - static YesType subclassCheck(U<W...>*); - static NoType subclassCheck(...); - static T* t; - - public: - static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); -}; - -template <typename T, template <typename V, size_t W> class U> -struct IsSubclassOfTemplateTypenameSize { - private: - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename X, size_t Y> - static YesType subclassCheck(U<X, Y>*); - static NoType subclassCheck(...); - static T* t; - - public: - static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); -}; - -template <typename T, template <typename V, size_t W, typename X> class U> -struct IsSubclassOfTemplateTypenameSizeTypename { - private: - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename Y, size_t Z, typename A> - static YesType subclassCheck(U<Y, Z, A>*); - static NoType subclassCheck(...); - static T* t; - - public: - static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType); -}; - -template <typename T, template <class V> class OuterTemplate> -struct RemoveTemplate { - typedef T Type; -}; - -template <typename T, template <class V> class OuterTemplate> -struct RemoveTemplate<OuterTemplate<T>, OuterTemplate> { - typedef T Type; -}; - -#if (COMPILER(MSVC) || !GCC_VERSION_AT_LEAST(4, 9, 0)) && !COMPILER(CLANG) -// FIXME: MSVC bug workaround. Remove once MSVC STL is fixed. -// FIXME: GCC before 4.9.0 seems to have the same issue. -// C++ 2011 Spec (ISO/IEC 14882:2011(E)) 20.9.6.2 Table 51 states that -// the template parameters shall be a complete type if they are different types. -// However, MSVC checks for type completeness even if they are the same type. -// Here, we use a template specialization for same type case to allow incomplete -// types. - -template <typename T, typename U> -struct IsConvertible { - static const bool value = std::is_convertible<T, U>::value; -}; - -template <typename T> -struct IsConvertible<T, T> { - static const bool value = true; -}; - -#define EnsurePtrConvertibleArgDecl(From, To) \ - typename std::enable_if<WTF::IsConvertible<From*, To*>::value>::type* = \ - nullptr -#define EnsurePtrConvertibleArgDefn(From, To) \ - typename std::enable_if<WTF::IsConvertible<From*, To*>::value>::type* -#else -#define EnsurePtrConvertibleArgDecl(From, To) \ - typename std::enable_if<std::is_convertible<From*, To*>::value>::type* = \ - nullptr -#define EnsurePtrConvertibleArgDefn(From, To) \ - typename std::enable_if<std::is_convertible<From*, To*>::value>::type* -#endif - -} // namespace WTF - -namespace blink { - -class Visitor; - -} // namespace blink - -namespace WTF { - -template <typename T> -class IsTraceable { - typedef char YesType; - typedef struct NoType { char padding[8]; } NoType; - - // Note that this also checks if a superclass of V has a trace method. - template <typename V> - static YesType checkHasTraceMethod( - V* v, - blink::Visitor* p = nullptr, - typename std::enable_if< - std::is_same<decltype(v->trace(p)), void>::value>::type* g = nullptr); - template <typename V> - static NoType checkHasTraceMethod(...); - - public: - // We add sizeof(T) to both sides here, because we want it to fail for - // incomplete types. Otherwise it just assumes that incomplete types do not - // have a trace method, which may not be true. - static const bool value = sizeof(YesType) + sizeof(T) == - sizeof(checkHasTraceMethod<T>(nullptr)) + sizeof(T); -}; - -// Convenience template wrapping the IsTraceableInCollection template in -// Collection Traits. It helps make the code more readable. -template <typename Traits> -class IsTraceableInCollectionTrait { - public: - static const bool value = Traits::template IsTraceableInCollection<>::value; -}; - -template <typename T, typename U> -struct IsTraceable<std::pair<T, U>> { - static const bool value = IsTraceable<T>::value || IsTraceable<U>::value; -}; - -// This is used to check that DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects are not -// stored in off-heap Vectors, HashTables etc. -template <typename T> -struct AllowsOnlyPlacementNew { - private: - using YesType = char; - struct NoType { - char padding[8]; - }; - - template <typename U> - static YesType checkMarker(typename U::IsAllowOnlyPlacementNew*); - template <typename U> - static NoType checkMarker(...); - - public: - static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType); -}; - -template <typename T> -class IsGarbageCollectedType { - typedef char YesType; - typedef struct NoType { char padding[8]; } NoType; - - static_assert(sizeof(T), "T must be fully defined"); - - using NonConstType = typename std::remove_const<T>::type; - template <typename U> - static YesType checkGarbageCollectedType( - typename U::IsGarbageCollectedTypeMarker*); - template <typename U> - static NoType checkGarbageCollectedType(...); - - // Separately check for GarbageCollectedMixin, which declares a different - // marker typedef, to avoid resolution ambiguity for cases like - // IsGarbageCollectedType<B> over: - // - // class A : public GarbageCollected<A>, public GarbageCollectedMixin { - // USING_GARBAGE_COLLECTED_MIXIN(A); - // ... - // }; - // class B : public A, public GarbageCollectedMixin { ... }; - // - template <typename U> - static YesType checkGarbageCollectedMixinType( - typename U::IsGarbageCollectedMixinMarker*); - template <typename U> - static NoType checkGarbageCollectedMixinType(...); - - public: - static const bool value = - (sizeof(YesType) == - sizeof(checkGarbageCollectedType<NonConstType>(nullptr))) || - (sizeof(YesType) == - sizeof(checkGarbageCollectedMixinType<NonConstType>(nullptr))); -}; - -template <> -class IsGarbageCollectedType<void> { - public: - static const bool value = false; -}; - -template <typename T> -class IsPersistentReferenceType { - typedef char YesType; - typedef struct NoType { char padding[8]; } NoType; - - template <typename U> - static YesType checkPersistentReferenceType( - typename U::IsPersistentReferenceTypeMarker*); - template <typename U> - static NoType checkPersistentReferenceType(...); - - public: - static const bool value = - (sizeof(YesType) == sizeof(checkPersistentReferenceType<T>(nullptr))); -}; - -template <typename T, - bool = std::is_function<typename std::remove_const< - typename std::remove_pointer<T>::type>::type>::value || - std::is_void<typename std::remove_const< - typename std::remove_pointer<T>::type>::type>::value> -class IsPointerToGarbageCollectedType { - public: - static const bool value = false; -}; - -template <typename T> -class IsPointerToGarbageCollectedType<T*, false> { - public: - static const bool value = IsGarbageCollectedType<T>::value; -}; - -} // namespace WTF - -using WTF::IsGarbageCollectedType; - -#endif // TypeTraits_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/build_config.h b/third_party/WebKit/Source/wtf/build_config.h index 5d0b90d..5980e3c 100644 --- a/third_party/WebKit/Source/wtf/build_config.h +++ b/third_party/WebKit/Source/wtf/build_config.h
@@ -1,57 +1,9 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2013 Apple Inc. - * Copyright (C) 2009 Google Inc. All rights reserved. - * Copyright (C) 2007-2009 Torch Mobile, Inc. - * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef WTF_build_config_h -#define WTF_build_config_h +#include "platform/wtf/build_config.h" -#include "build/build_config.h" -#include "wtf/Compiler.h" - -/* ==== Platform adaptation macros: these describe properties of the target - * environment. ==== */ - -/* HAVE() - specific system features (headers, functions or similar) that are - * present or not */ -#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE) -/* OS() - underlying operating system; only to be used for mandated low-level - services like - virtual memory, not to choose a GUI toolkit */ -#define OS(WTF_FEATURE) (defined OS_##WTF_FEATURE && OS_##WTF_FEATURE) - -/* ==== Policy decision macros: these define policy choices for a particular - * port. ==== */ - -/* USE() - use a particular third-party library or optional OS service */ -#define USE(WTF_FEATURE) \ - (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE) -/* ENABLE() - turn on a specific feature of WebKit */ -#define ENABLE(WTF_FEATURE) \ - (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE) - -/* There is an assumption in the project that either OS(WIN) or OS(POSIX) is - * set. */ -#if !OS(WIN) && !OS(POSIX) -#error Either OS(WIN) or OS(POSIX) needs to be set. -#endif - -#endif // WTF_build_config_h +// The contents of this header was moved to platform/wtf as part of +// WTF migration project. See the following post for details: +// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py index 831d26ce..61ca77f 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/bindings/bindings_tests.py
@@ -77,7 +77,7 @@ # core/inspector/InspectorInstrumentation.idl is not a valid Blink IDL. NON_BLINK_IDL_FILES = frozenset([ - 'InspectorInstrumentation.idl', + 'InstrumentingProbes.idl', ]) COMPONENT_DIRECTORY = frozenset(['core', 'modules'])
diff --git a/third_party/WebKit/public/web/WebFrameOwnerProperties.h b/third_party/WebKit/public/web/WebFrameOwnerProperties.h index 5ba8d741..9dce98f 100644 --- a/third_party/WebKit/public/web/WebFrameOwnerProperties.h +++ b/third_party/WebKit/public/web/WebFrameOwnerProperties.h
@@ -8,7 +8,6 @@ #include "../platform/WebFeaturePolicy.h" #include "../platform/WebString.h" #include "../platform/WebVector.h" -#include "third_party/WebKit/public/platform/modules/permissions/permission.mojom-shared.h" #include <algorithm> @@ -24,7 +23,6 @@ bool allowFullscreen; bool allowPaymentRequest; WebString requiredCsp; - WebVector<mojom::PermissionName> delegatedPermissions; public: WebVector<WebFeaturePolicyFeature> allowedFeatures; @@ -45,7 +43,6 @@ bool allowFullscreen, bool allowPaymentRequest, const WebString& requiredCsp, - const WebVector<mojom::PermissionName>& delegatedPermissions, const WebVector<WebFeaturePolicyFeature>& allowedFeatures) : name(name), scrollingMode(static_cast<ScrollingMode>(scrollingMode)), @@ -54,7 +51,6 @@ allowFullscreen(allowFullscreen), allowPaymentRequest(allowPaymentRequest), requiredCsp(requiredCsp), - delegatedPermissions(delegatedPermissions), allowedFeatures(allowedFeatures) {} #endif };
diff --git a/third_party/WebKit/public/web/WebPlugin.h b/third_party/WebKit/public/web/WebPlugin.h index 8d2078b..6e6403a7 100644 --- a/third_party/WebKit/public/web/WebPlugin.h +++ b/third_party/WebKit/public/web/WebPlugin.h
@@ -167,19 +167,23 @@ } // Sets composition text from input method, and returns true if the - // composition is set successfully. + // composition is set successfully. If |replacementRange| is not null, the + // text inside |replacementRange| will be replaced by |text| virtual bool setComposition( const WebString& text, const WebVector<WebCompositionUnderline>& underlines, + const WebRange& replacementRange, int selectionStart, int selectionEnd) { return false; } // Deletes the ongoing composition if any, inserts the specified text, and - // moves the caret according to relativeCaretPosition. + // moves the caret according to relativeCaretPosition. If |replacementRange| + // is not null, the text inside |replacementRange| will be replaced by |text|. virtual bool commitText(const WebString& text, const WebVector<WebCompositionUnderline>& underlines, + const WebRange& replacementRange, int relativeCaretPosition) { return false; }
diff --git a/third_party/closure_compiler/README.chromium b/third_party/closure_compiler/README.chromium index a0ef64d..e02ecbe 100644 --- a/third_party/closure_compiler/README.chromium +++ b/third_party/closure_compiler/README.chromium
@@ -3,7 +3,7 @@ URL: http://github.com/google/closure-compiler Version: v20150729-236-gad656a1 Date: 2015/08/26 08:46 -Revision: 72c88ff7e9e85b4c2413274539897b6d43024d48 +Revision: b2f2d2f3309c7ee61816e068050651af27bccdfa License: Apache 2.0 License File: LICENSE Security Critical: no
diff --git a/third_party/closure_compiler/compiler/compiler.jar b/third_party/closure_compiler/compiler/compiler.jar index c57eed9..a895591 100644 --- a/third_party/closure_compiler/compiler/compiler.jar +++ b/third_party/closure_compiler/compiler/compiler.jar Binary files differ
diff --git a/third_party/closure_compiler/externs/chrome_extensions.js b/third_party/closure_compiler/externs/chrome_extensions.js index ac0cd611..7088c14 100644 --- a/third_party/closure_compiler/externs/chrome_extensions.js +++ b/third_party/closure_compiler/externs/chrome_extensions.js
@@ -2559,7 +2559,7 @@ /** * @const - * @see https://developer.chrome.com/extensions/tabs.html + * @see https://developer.chrome.com/extensions/tabs */ chrome.tabs = {}; @@ -2770,7 +2770,11 @@ * @typedef {?{ * active: (boolean|undefined), * pinned: (boolean|undefined), + * audible: (boolean|undefined), + * muted: (boolean|undefined), * highlighted: (boolean|undefined), + * discarded: (boolean|undefined), + * autoDiscardable: (boolean|undefined), * currentWindow: (boolean|undefined), * lastFocusedWindow: (boolean|undefined), * status: (!chrome.tabs.TabStatus|string|undefined), @@ -6028,18 +6032,17 @@ /** * Most event listeners for WebRequest take extra arguments. - * @see https://developer.chrome.com/extensions/webRequest.html. + * @see https://developer.chrome.com/extensions/webRequest * @constructor */ function WebRequestEvent() {} /** - * @param {function(!Object): (void|!BlockingResponse)} listener Listener - * function. + * @param {function(!Object): void} listener Listener function. * @param {!RequestFilter} filter A set of filters that restrict * the events that will be sent to this listener. - * @param {Array<string>=} opt_extraInfoSpec Array of extra information + * @param {!Array<string>=} opt_extraInfoSpec Array of extra information * that should be passed to the listener function. * @return {undefined} */ @@ -6048,33 +6051,123 @@ /** - * @param {function(!Object): (void|!BlockingResponse)} listener Listener - * function. + * @param {function(!Object): void} listener Listener function. * @return {undefined} */ WebRequestEvent.prototype.removeListener = function(listener) {}; /** - * @param {function(!Object): (void|!BlockingResponse)} listener Listener - * function. + * @param {function(!Object): void} listener Listener function. * @return {undefined} */ WebRequestEvent.prototype.hasListener = function(listener) {}; /** - * @param {function(!Object): (void|!BlockingResponse)} listener Listener - * function. + * @param {function(!Object): void} listener Listener function. * @return {undefined} */ WebRequestEvent.prototype.hasListeners = function(listener) {}; +/** + * Some event listeners can be optionally synchronous. + * @see https://developer.chrome.com/extensions/webRequest + * @constructor + */ +function WebRequestOptionallySynchronousEvent() {} + /** - * The onErrorOccurred event takes one less parameter than the others. - * @see https://developer.chrome.com/extensions/webRequest.html. + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @param {!RequestFilter} filter A set of filters that restrict + * the events that will be sent to this listener. + * @param {!Array<string>=} opt_extraInfoSpec Array of extra information + * that should be passed to the listener function. + * @return {undefined} + */ +WebRequestOptionallySynchronousEvent.prototype.addListener = function( + listener, filter, opt_extraInfoSpec) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOptionallySynchronousEvent.prototype.removeListener = function( + listener) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOptionallySynchronousEvent.prototype.hasListener = function( + listener) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOptionallySynchronousEvent.prototype.hasListeners = function( + listener) {}; + + +/** + * The onAuthRequired event listener can be optionally synchronous, and can also + * optionally take a callback. + * @see https://developer.chrome.com/extensions/webRequest + * @constructor + */ +function WebRequestOnAuthRequiredEvent() {} + + +/** + * @param {function(!Object, function(!BlockingResponse)=): + * (undefined|!BlockingResponse)} listener Listener function. + * @param {!RequestFilter} filter A set of filters that restrict + * the events that will be sent to this listener. + * @param {!Array<string>=} opt_extraInfoSpec Array of extra information + * that should be passed to the listener function. + * @return {undefined} + */ +WebRequestOnAuthRequiredEvent.prototype.addListener = function( + listener, filter, opt_extraInfoSpec) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOnAuthRequiredEvent.prototype.removeListener = function(listener) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOnAuthRequiredEvent.prototype.hasListener = function(listener) {}; + + +/** + * @param {function(!Object): (undefined|!BlockingResponse)} listener Listener + * function. + * @return {undefined} + */ +WebRequestOnAuthRequiredEvent.prototype.hasListeners = function(listener) {}; + + +/** + * The onErrorOccurred event takes one fewer parameter than the others. + * @see https://developer.chrome.com/extensions/webRequest * @constructor */ function WebRequestOnErrorOccurredEvent() {} @@ -6113,7 +6206,7 @@ /** * @const - * @see https://developer.chrome.com/extensions/webRequest.html + * @see https://developer.chrome.com/extensions/webRequest */ chrome.webRequest = {}; @@ -6125,7 +6218,7 @@ chrome.webRequest.handlerBehaviorChanged = function(opt_callback) {}; -/** @type {!WebRequestEvent} */ +/** @type {!WebRequestOnAuthRequiredEvent} */ chrome.webRequest.onAuthRequired; @@ -6133,11 +6226,11 @@ chrome.webRequest.onBeforeRedirect; -/** @type {!WebRequestEvent} */ +/** @type {!WebRequestOptionallySynchronousEvent} */ chrome.webRequest.onBeforeRequest; -/** @type {!WebRequestEvent} */ +/** @type {!WebRequestOptionallySynchronousEvent} */ chrome.webRequest.onBeforeSendHeaders; @@ -6149,7 +6242,7 @@ chrome.webRequest.onErrorOccurred; -/** @type {!WebRequestEvent} */ +/** @type {!WebRequestOptionallySynchronousEvent} */ chrome.webRequest.onHeadersReceived; @@ -7034,82 +7127,49 @@ /** - * @see https://developer.chrome.com/extensions/webRequest.html#type-RequestFilter - * @constructor + * @see https://developer.chrome.com/extensions/webRequest#type-RequestFilter + * @typedef {?{ + * urls: !Array<string>, + * types: (!Array<string>|undefined), + * tabId: (number|undefined), + * windowId: (number|undefined), + * }} */ -function RequestFilter() {} - - -/** @type {!Array<string>} */ -RequestFilter.prototype.urls; - - -/** @type {!Array<string>} */ -RequestFilter.prototype.types; - - -/** @type {number} */ -RequestFilter.prototype.tabId; - - -/** @type {number} */ -RequestFilter.prototype.windowId; +var RequestFilter; /** - * @see https://developer.chrome.com/extensions/webRequest.html#type-HttpHeaders - * @constructor + * @see https://developer.chrome.com/extensions/webRequest#type-HttpHeaders + * @typedef {?{ + * name: string, + * value: (string|undefined), + * binaryValue: (!Array<number>|undefined), + * }} */ -function HttpHeader() {} - - -/** @type {string} */ -HttpHeader.prototype.name; - - -/** @type {string} */ -HttpHeader.prototype.value; - - -/** @type {!Array<number>} */ -HttpHeader.prototype.binaryValue; - - -/** - * @see https://developer.chrome.com/extensions/webRequest.html#type-HttpHeaders - * @typedef {Array<!HttpHeader>} - * @private - */ -var HttpHeaders_; +var HttpHeader; /** - * @see https://developer.chrome.com/extensions/webRequest.html#type-BlockingResponse - * @constructor + * @see https://developer.chrome.com/extensions/webRequest#type-HttpHeaders + * @typedef {?Array<!HttpHeader>} */ -function BlockingResponse() {} +chrome.webRequest.HttpHeaders; -/** @type {boolean} */ -BlockingResponse.prototype.cancel; - -/** @type {string} */ -BlockingResponse.prototype.redirectUrl; - - -/** @type {!HttpHeaders_} */ -BlockingResponse.prototype.requestHeaders; - - -/** @type {!HttpHeaders_} */ -BlockingResponse.prototype.responseHeaders; - - -/** @type {Object<string,string>} */ -BlockingResponse.prototype.authCredentials; +/** + * @see https://developer.chrome.com/extensions/webRequest#type-BlockingResponse + * @typedef {?{ + * cancel: (boolean|undefined), + * redirectUrl: (string|undefined), + * requestHeaders: (!chrome.webRequest.HttpHeaders|undefined), + * responseHeaders: (!chrome.webRequest.HttpHeaders|undefined), + * authCredentials: (!{username: string, password: string}|undefined), + * }} + */ +var BlockingResponse; @@ -9980,6 +10040,13 @@ /** * @param {string} deviceAddress * @param {function():void=} callback + */ +chrome.bluetoothPrivate.disconnectAll = function(deviceAddress, callback) {}; + + +/** + * @param {string} deviceAddress + * @param {function():void=} callback * @return {undefined} */ chrome.bluetoothPrivate.forgetDevice = function(deviceAddress, callback) {};
diff --git a/third_party/closure_compiler/externs/compiled_resources2.gyp b/third_party/closure_compiler/externs/compiled_resources2.gyp index 488f6de..7aab119 100644 --- a/third_party/closure_compiler/externs/compiled_resources2.gyp +++ b/third_party/closure_compiler/externs/compiled_resources2.gyp
@@ -1,4 +1,4 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -81,7 +81,7 @@ 'includes': ['../include_js.gypi'], }, { - 'target_name': 'pending_compiler_externs', + 'target_name': 'polymer-1.0', 'includes': ['../include_js.gypi'], }, { @@ -109,4 +109,4 @@ 'includes': ['../include_js.gypi'], }, ], -} +} \ No newline at end of file
diff --git a/third_party/closure_compiler/externs/pending_compiler_externs.js b/third_party/closure_compiler/externs/pending_compiler_externs.js deleted file mode 100644 index 9dd3216..0000000 --- a/third_party/closure_compiler/externs/pending_compiler_externs.js +++ /dev/null
@@ -1,12 +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. - -/** @externs */ - -/** - * @type {?Document} - * @see w3c_dom2.js - * @see http://www.w3.org/TR/html-imports/#interface-import - */ -HTMLLinkElement.prototype.import;
diff --git a/third_party/closure_compiler/externs/web_animations.js b/third_party/closure_compiler/externs/web_animations.js index 39ffc37..c233999 100644 --- a/third_party/closure_compiler/externs/web_animations.js +++ b/third_party/closure_compiler/externs/web_animations.js
@@ -187,13 +187,6 @@ Animation.prototype.cancel = function() {}; -/** - * @param {boolean=} opt_useCapture - * @override - */ -Animation.prototype.addEventListener = function( - type, listener, opt_useCapture) {}; - /** @type {EventHandler} */ Animation.prototype.onfinish;
diff --git a/third_party/closure_compiler/roll_closure_compiler b/third_party/closure_compiler/roll_closure_compiler index ca11c79f..fa8d01e 100755 --- a/third_party/closure_compiler/roll_closure_compiler +++ b/third_party/closure_compiler/roll_closure_compiler
@@ -64,7 +64,7 @@ fi echo "Building Closure Compiler" -mvn install -DskipTests=true --projects com.google.javascript:closure-compiler +mvn clean install -DskipTests=true --projects com.google.javascript:closure-compiler,com.google.javascript:closure-compiler-externs if [[ "$?" -ne 0 ]]; then echo "Failed to build jar, copying nothing" >&2
diff --git a/third_party/closure_compiler/tools/create_include_gyp.py b/third_party/closure_compiler/tools/create_include_gyp.py index 2258e0ce..08ef525 100755 --- a/third_party/closure_compiler/tools/create_include_gyp.py +++ b/third_party/closure_compiler/tools/create_include_gyp.py
@@ -46,7 +46,7 @@ def ShowUsageAndDie(): - print "usage: tools/create_include_gyp.py externs > externs/compiled_resources2.gyp" + print "usage: tools/create_include_gyp.py externs/ > externs/compiled_resources2.gyp" sys.exit(1)
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni index 84373f3..880a5af4 100644 --- a/third_party/protobuf/proto_library.gni +++ b/third_party/protobuf/proto_library.gni
@@ -285,7 +285,7 @@ if (defined(invoker.import_dirs)) { foreach(path, invoker.import_dirs) { - args += ["--import-dir=" + rebase_path(path, root_build_dir)] + args += [ "--import-dir=" + rebase_path(path, root_build_dir) ] } } @@ -373,6 +373,16 @@ "//third_party/protobuf:protobuf_lite", ] } + + if (is_win) { + cflags = [ + # disable: C4125 decimal digit terminates octal escape sequence + # Protoc generates such sequences frequently, there's no obvious + # superior replacement behavior. Since this code is autogenerated, + # the warning would never catch a legitimate bug. + "/wd4125", + ] + } } }
diff --git a/third_party/tcmalloc/BUILD.gn b/third_party/tcmalloc/BUILD.gn new file mode 100644 index 0000000..ea10b28 --- /dev/null +++ b/third_party/tcmalloc/BUILD.gn
@@ -0,0 +1,14 @@ +# Copyright (c) 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/compiler/compiler.gni") + +executable("addr2line-pdb") { + sources = [ + "chromium/src/windows/addr2line-pdb.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] +}
diff --git a/third_party/tcmalloc/README.chromium b/third_party/tcmalloc/README.chromium index d2e8176..50862f9 100644 --- a/third_party/tcmalloc/README.chromium +++ b/third_party/tcmalloc/README.chromium
@@ -105,3 +105,5 @@ - Added TCMALLOC_DONT_REPLACE_SYSTEM_ALLOC which bypasses the libc_override logic. - Backported 7df7f14 "issue-693: enable futex usage on arm" from upstream. - Don't use the tls model 'initial-exec' in chromeos on arm with gcc. +- Update addr2line-pdb.c to fix format string errors and use relative addresses + matching linux's behavior more closely.
diff --git a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c index 97b614b4..7a2bf3e6 100644 --- a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c +++ b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
@@ -35,9 +35,17 @@ * c:\websymbols without asking. */ +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE +#endif #include <stdio.h> #include <stdlib.h> @@ -67,7 +75,8 @@ } else if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) { symopts |= SYMOPT_UNDNAME; - } else if (strcmp(argv[i], "-e") == 0) { + } else if (strcmp(argv[i], "--exe") == 0 || + strcmp(argv[i], "-e") == 0) { if (i + 1 >= argc) { fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n"); return 1; @@ -86,7 +95,7 @@ if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); - fprintf(stderr, "SymInitialize returned error : %d\n", error); + fprintf(stderr, "SymInitialize returned error : %lu\n", error); return 1; } @@ -100,13 +109,13 @@ strcat(search, ";" WEBSYM); } else { error = GetLastError(); - fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); + fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); - fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); + fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ } @@ -115,7 +124,7 @@ if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); - fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", + fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n", error, filename); SymCleanup(process); return 1; @@ -126,7 +135,7 @@ /* GNU addr2line seems to just do a strtol and ignore any * weird characters it gets, so we will too. */ - unsigned __int64 addr = _strtoui64(buf, NULL, 16); + unsigned __int64 reladdr = _strtoui64(buf, NULL, 16); ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) @@ -134,17 +143,25 @@ PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; IMAGEHLP_LINE64 line; DWORD dummy; + + // Just ignore overflow. In an overflow scenario, the resulting address + // will be lower than module_base which hasn't been mapped by any prior + // SymLoadModuleEx() command. This will cause SymFromAddr() and + // SymGetLineFromAddr64() both to return failures and print the correct + // ?? and ??:0 message variant. + ULONG64 absaddr = reladdr + module_base; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; if (print_function_name) { - if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) { + if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) { printf("%s\n", pSymbol->Name); } else { printf("??\n"); } } line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) { + if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) { printf("%s:%d\n", line.FileName, (int)line.LineNumber); } else { printf("??:0\n");
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 2125245..917f3c6 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1086,10 +1086,14 @@ output_path=None) if android and test_type != "script": + # TODO(crbug.com/693203): Reenable logcat logdog uploading when outage + # has been resolved. cmdline = [ - '../../build/android/test_wrapper/logdog_wrapper.py', - '--target', target, - '--logdog-bin-cmd', '../../bin/logdog_butler'] + self.PathJoin('bin', 'run_%s' % target), + '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats', + '--target-devices-file', '${SWARMING_BOT_FILE}', + '-v' + ] elif use_xvfb and test_type == 'windowed_test_launcher': extra_files = [ '../../testing/test_env.py',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index c9f01f39..a845aed 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -564,6 +564,7 @@ 'linux_chromium_gn_upload': 'gn_linux_upload', 'linux_chromium_headless_rel': 'headless_linux_release_trybot', 'linux_chromium_ozone_compile_only_ng': 'ozone_linux_release_trybot', + 'linux_chromium_ozone_ng': 'ozone_linux_release_trybot', # This is intentionally a release_bot and not a release_trybot; # enabling DCHECKs seems to cause flaky failures that don't show up @@ -1830,6 +1831,7 @@ 'ozone_linux': { 'gn_args': ('ozone_auto_platforms=false ozone_platform_wayland=true ' + 'ozone_platform="x11" ' 'ozone_platform_x11=true ozone_platform_gbm=true ' 'enable_package_mash_services=true use_ash=false ' 'use_jessie_sysroot=true use_xkbcommon=true'),
diff --git a/tools/md_browser/md_browser.py b/tools/md_browser/md_browser.py index 2c416433..d3594bf 100755 --- a/tools/md_browser/md_browser.py +++ b/tools/md_browser/md_browser.py
@@ -138,6 +138,10 @@ self._DoMD(path) elif os.path.exists(full_path + '/README.md'): self._DoMD(path + '/README.md') + elif path.lower().endswith('.png'): + self._DoImage(full_path, 'image/png') + elif path.lower().endswith('.jpg'): + self._DoImage(full_path, 'image/jpeg') else: self._DoDirListing(full_path) @@ -223,6 +227,12 @@ self._WriteTemplate('footer.html') + def _DoImage(self, full_path, mime_type): + self._WriteHeader(mime_type) + with open(full_path) as f: + self.wfile.write(f.read()) + f.close() + def _Read(self, relpath, relative_to=None): if relative_to is None: relative_to = self.server.top_level
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index ad8770a..9dab252 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -17676,6 +17676,10 @@ <histogram name="Extensions.DisabledUIUserResponse" enum="ExtensionDisabledUIUserResponse"> + <obsolete> + Deprecated 03/2017 because miscounting IGNORE histogram entry. This error is + fixed with DisabledUIUserResponse2. + </obsolete> <owner>rdevlin.cronin@chromium.org</owner> <summary> User response to the dialog shown when an extension is disabled due to an @@ -17683,8 +17687,23 @@ </summary> </histogram> +<histogram name="Extensions.DisabledUIUserResponse2" + enum="ExtensionDisabledUIUserResponse"> + <owner>catmullings@chromium.org</owner> + <summary> + User response to the dialog shown when an extension is disabled due to an + update requiring more permissions. A count is recorded when the user takes + an action on the dialog (re-enable or remove the extension) or ignores the + dialog. + </summary> +</histogram> + <histogram name="Extensions.DisabledUIUserResponseRemoteInstall" enum="ExtensionDisabledUIUserResponse"> + <obsolete> + Deprecated 03/2017 because miscounting IGNORE histogram entry. This error is + fixed with DisabledUIUserResponseRemoteInstall2. + </obsolete> <owner>mek@chromium.org</owner> <summary> User response to the dialog shown when an extension is disabled due to it @@ -17692,6 +17711,17 @@ </summary> </histogram> +<histogram name="Extensions.DisabledUIUserResponseRemoteInstall2" + enum="ExtensionDisabledUIUserResponse"> + <owner>catmullings@chromium.org</owner> + <summary> + User response to the dialog shown when an extension is disabled due to it + having been installed remotely. A count is recorded when the user takes an + action on the dialog (re-enable or remove the extension) or ignores the + dialog. + </summary> +</histogram> + <histogram name="Extensions.DisableReason" enum="ExtensionDisableReason"> <owner>asargent@chromium.org</owner> <summary> @@ -24514,6 +24544,15 @@ </summary> </histogram> +<histogram name="LibraryLoader.LoadNativeLibraryWindows" + enum="LoadLibraryResultCategory"> + <owner>chengx@chromium.org</owner> + <summary> + This metric records the LoadLibraryExW and LoadLibraryW Windows API call + results, which are used in native_library_win.cc. + </summary> +</histogram> + <histogram name="LibraryLoader.NativeLibraryHack" enum="BooleanUsage"> <obsolete> Deprecated as of 11/2014, removed from code. @@ -28322,6 +28361,28 @@ </summary> </histogram> +<histogram base="true" name="Memory.OpenFDs" units="files"> +<!-- Name completed by histogram_suffixes name="MemoryFDsBroswerGpuAndRendererProcess" and name="MemoryFDsAllProcesses" --> + + <owner>dcastagna@chromium.org</owner> + <owner>primiano@chromium.org</owner> + <summary> + The total number of open file descriptors opened per process. Recorded once + per UMA ping. + </summary> +</histogram> + +<histogram base="true" name="Memory.OpenFDsSoftLimit" units="files"> +<!-- Name completed by histogram_suffixes name="MemoryFDsBroswerGpuAndRendererProcess" --> + + <owner>dcastagna@chromium.org</owner> + <owner>primiano@chromium.org</owner> + <summary> + The limit of open file descriptors that can be opened per process. Recorded + once per UMA ping. + </summary> +</histogram> + <histogram name="Memory.OtherProcessCount" units="processes"> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> @@ -85109,6 +85170,8 @@ <int value="2" label="Clicked 'Always allow pop-ups from'"/> <int value="3" label="Clicked one of the list items"/> <int value="4" label="Clicked 'Manage pop-up blocking'"/> + <int value="5" label="Displayed popup-blocked infobar on mobile"/> + <int value="6" label="Clicked 'Always show on mobile'"/> </enum> <enum name="ContentSettingScheme" type="int"> @@ -93403,6 +93466,7 @@ <int value="1864" label="VRPoseLinearAcceleration"/> <int value="1865" label="VRPoseAngularVelocity"/> <int value="1866" label="VRPoseAngularAcceleration"/> + <int value="1867" label="CSSOverflowPaged"/> </enum> <enum name="FetchRequestMode" type="int"> @@ -99013,6 +99077,14 @@ <int value="23" label="Unnamed"/> </enum> +<enum name="LoadLibraryResultCategory" type="int"> + <int value="0" label="LoadLibraryExW Succeeded"/> + <int value="1" label="LoadLibraryExW Fail, LoadLibraryW Succeeded"/> + <int value="2" label="LoadLibraryExW Fail, LoadLibraryW Fail"/> + <int value="3" label="LoadLibraryExW Unavailable, LoadLibraryW Succeeded"/> + <int value="4" label="LoadLibraryExW Unavailable, LoadLibraryW Fail"/> +</enum> + <enum name="LoadType" type="int"> <int value="0" label="UNDEFINED_LOAD">Not yet initialized</int> <int value="1" label="RELOAD">User pressed reload</int> @@ -117680,6 +117752,32 @@ <affected-histogram name="Media.WebMediaPlayerImpl.Memory"/> </histogram_suffixes> +<histogram_suffixes name="MemoryFDsAllProcesses" separator="." + ordering="prefix"> + <suffix name="Browser" label="Browser process"/> + <suffix name="Gpu" label="GPU process"/> + <suffix name="RendererAll" label="Renderer process"/> + <suffix name="Chrome" label="chrome:// renderer process"/> + <suffix name="Extension" label="Extension process"/> + <suffix name="NativeClient" label="Native client process"/> + <suffix name="NativeClientBroker" label="Native client broker process"/> + <suffix name="PeperPlugin" label="Pepper plugin process"/> + <suffix name="PepperPluginBroker" label="Pepper plugin broker process"/> + <suffix name="Renderer" label="Renderer process"/> + <suffix name="SandboxHelper" label="Sandbox helper process"/> + <suffix name="Utility" label="Utility process"/> + <suffix name="Zygote" label="Zygot process"/> + <affected-histogram name="Memory.OpenFDs"/> +</histogram_suffixes> + +<histogram_suffixes name="MemoryFDsBroswerGpuAndRendererProcess" separator="." + ordering="prefix"> + <suffix name="Browser" label="Browser process"/> + <suffix name="Gpu" label="GPU process"/> + <suffix name="RendererAll" label="Renderer process"/> + <affected-histogram name="Memory.OpenFDsSoftLimit"/> +</histogram_suffixes> + <histogram_suffixes name="MemoryStateTransition" separator="."> <suffix name="NormalToThrottled"/> <suffix name="NormalToSuspended"/> @@ -119994,6 +120092,16 @@ <affected-histogram name="PageLoad.ParseTiming.ParseDuration"/> </histogram_suffixes> +<histogram_suffixes name="PageLoadMetricsClientsMedia" separator="." + ordering="prefix"> + <suffix name="Clients.Media" + label="PageLoadMetrics for page loads that involved playing a media + element."/> + <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/> + <affected-histogram name="PageLoad.Experimental.Bytes.Network"/> + <affected-histogram name="PageLoad.Experimental.Bytes.Total"/> +</histogram_suffixes> + <histogram_suffixes name="PageLoadMetricsClientsOfflinePages" separator="." ordering="prefix"> <suffix name="Clients.Previews.OfflinePages"
diff --git a/ui/file_manager/externs/webview_tag.js b/ui/file_manager/externs/webview_tag.js index 7bea1fd..cc6eb452 100644 --- a/ui/file_manager/externs/webview_tag.js +++ b/ui/file_manager/externs/webview_tag.js
@@ -188,12 +188,12 @@ /** * @constructor - * @see https://developer.chrome.com/apps/tags/webview#type-WebRequestEventInteface + * @see https://developer.chrome.com/apps/tags/webview#type-WebRequestEventInterface */ -function WebRequestEventInteface() {} +function WebRequestEventInterface() {} -/** @type {!WebRequestEvent} */ -WebRequestEventInteface.prototype.onBeforeSendHeaders; +/** @type {!WebRequestOptionallySynchronousEvent} */ +WebRequestEventInterface.prototype.onBeforeSendHeaders; /** * @constructor @@ -208,7 +208,7 @@ WebView.prototype.contentWindow; /** - * @type {!WebRequestEventInteface} + * @type {!WebRequestEventInterface} * @see https://developer.chrome.com/apps/tags/webview#property-request */ WebView.prototype.request;
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn index 23cd695..42fe36d1 100644 --- a/ui/gfx/BUILD.gn +++ b/ui/gfx/BUILD.gn
@@ -50,12 +50,6 @@ "android/view_configuration.cc", "android/view_configuration.h", "break_list.h", - "codec/jpeg_codec.cc", - "codec/jpeg_codec.h", - "codec/png_codec.cc", - "codec/png_codec.h", - "codec/skia_image_encoder_adapter.cc", - "codec/skia_image_encoder_adapter.h", "color_analysis.cc", "color_analysis.h", "color_palette.h", @@ -255,6 +249,7 @@ "//skia", "//third_party/icu", "//ui/gfx/animation", + "//ui/gfx/codec", "//ui/gfx/geometry", "//ui/gfx/range", ] @@ -265,7 +260,6 @@ "//base:i18n", "//base/third_party/dynamic_annotations", "//skia", - "//third_party/libpng", "//third_party/qcms", "//third_party/zlib", ] @@ -305,17 +299,12 @@ # iOS. if (is_ios) { - sources -= [ - "codec/jpeg_codec.cc", - "codec/jpeg_codec.h", - ] set_sources_assignment_filter([]) sources += [ "scoped_cg_context_save_gstate_mac.h" ] set_sources_assignment_filter(sources_assignment_filter) } else { deps += [ "//cc/paint", - "//third_party:jpeg", "//third_party/harfbuzz-ng", ] } @@ -358,9 +347,6 @@ # Windows. if (is_win) { - cflags = [ "/wd4324" ] # Structure was padded due to __declspec(align()), which is - # uninteresting. - libs = [ "setupapi.lib", "dwrite.lib", @@ -381,16 +367,6 @@ deps += [ "//build/linux:fontconfig" ] } - # Chrome OS - if (is_chromeos) { - # Robust JPEG decoding for the login screen. - sources += [ - "chromeos/codec/jpeg_codec_robust_slow.cc", - "chromeos/codec/jpeg_codec_robust_slow.h", - ] - deps += [ "//third_party/libjpeg" ] - } - if (is_mac) { libs = [ "AppKit.framework", @@ -718,7 +694,7 @@ } if (is_chromeos) { - sources += [ "chromeos/codec/jpeg_codec_robust_slow_unittest.cc" ] + sources += [ "codec/chromeos/jpeg_codec_robust_slow_unittest.cc" ] } if (is_win) {
diff --git a/ui/gfx/codec/BUILD.gn b/ui/gfx/codec/BUILD.gn new file mode 100644 index 0000000..6cdc8a7c --- /dev/null +++ b/ui/gfx/codec/BUILD.gn
@@ -0,0 +1,51 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/ui.gni") + +component("codec") { + sources = [ + "codec_export.h", + "jpeg_codec.cc", + "jpeg_codec.h", + "png_codec.cc", + "png_codec.h", + "skia_image_encoder_adapter.cc", + "skia_image_encoder_adapter.h", + ] + + deps = [ + "//base", + "//skia", + "//third_party/libpng", + "//ui/gfx:geometry_skia", + "//ui/gfx:gfx_export", + "//ui/gfx/geometry", + ] + + if (is_ios) { + sources -= [ + "jpeg_codec.cc", + "jpeg_codec.h", + ] + } else { + deps += [ "//third_party:jpeg" ] + } + + if (is_chromeos) { + # Robust JPEG decoding for the login screen. + sources += [ + "chromeos/jpeg_codec_robust_slow.cc", + "chromeos/jpeg_codec_robust_slow.h", + ] + deps += [ "//third_party/libjpeg" ] + } + + if (is_win) { + cflags = [ "/wd4324" ] # Structure was padded due to __declspec(align()), + # which is uninteresting. + } + + defines = [ "CODEC_IMPLEMENTATION" ] +}
diff --git a/ui/gfx/chromeos/codec/DEPS b/ui/gfx/codec/chromeos/DEPS similarity index 100% rename from ui/gfx/chromeos/codec/DEPS rename to ui/gfx/codec/chromeos/DEPS
diff --git a/ui/gfx/chromeos/codec/OWNERS b/ui/gfx/codec/chromeos/OWNERS similarity index 100% rename from ui/gfx/chromeos/codec/OWNERS rename to ui/gfx/codec/chromeos/OWNERS
diff --git a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow.cc b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc similarity index 95% rename from ui/gfx/chromeos/codec/jpeg_codec_robust_slow.cc rename to ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc index b7ceefd..057dd31e 100644 --- a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow.cc +++ b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc
@@ -2,21 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h" +#include "ui/gfx//codec/chromeos/jpeg_codec_robust_slow.h" #include <setjmp.h> #include <memory> #include "base/logging.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkColorPriv.h" extern "C" { // IJG provides robust JPEG decode #include "third_party/libjpeg/jpeglib.h" } +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColorPriv.h" + namespace gfx { // Encoder/decoder shared stuff ------------------------------------------------ @@ -30,7 +31,7 @@ }; void ErrorExit(jpeg_common_struct* cinfo) { - CoderErrorMgr *err = reinterpret_cast<CoderErrorMgr*>(cinfo->err); + CoderErrorMgr* err = reinterpret_cast<CoderErrorMgr*>(cinfo->err); // Return control to the setjmp point. longjmp(err->setjmp_buffer, false); @@ -44,8 +45,7 @@ struct JpegDecoderState { JpegDecoderState(const unsigned char* in, size_t len) - : input_buffer(in), input_buffer_length(len) { - } + : input_buffer(in), input_buffer_length(len) {} const unsigned char* input_buffer; size_t input_buffer_length; @@ -112,8 +112,7 @@ // "Terminate source --- called by jpeg_finish_decompress() after all data has // been read to clean up JPEG source manager. NOT called by jpeg_abort() or // jpeg_destroy()." -void TermSource(j_decompress_ptr cinfo) { -} +void TermSource(j_decompress_ptr cinfo) {} #if !defined(JCS_EXTENSIONS) // Converts one row of rgb data to rgba data by adding a fully-opaque alpha @@ -127,8 +126,7 @@ // Converts one row of RGB data to BGRA by reordering the color components and // adding alpha values of 0xff. -void RGBtoBGRA(const unsigned char* bgra, int pixel_width, unsigned char* rgb) -{ +void RGBtoBGRA(const unsigned char* bgra, int pixel_width, unsigned char* rgb) { for (int x = 0; x < pixel_width; x++) { const unsigned char* pixel_in = &bgra[x * 3]; unsigned char* pixel_out = &rgb[x * 4]; @@ -145,11 +143,8 @@ // success case). class DecompressDestroyer { public: - DecompressDestroyer() : cinfo_(NULL) { - } - ~DecompressDestroyer() { - DestroyManagedObject(); - } + DecompressDestroyer() : cinfo_(NULL) {} + ~DecompressDestroyer() { DestroyManagedObject(); } void SetManagedObject(jpeg_decompress_struct* ci) { DestroyManagedObject(); cinfo_ = ci; @@ -160,15 +155,18 @@ cinfo_ = NULL; } } + private: jpeg_decompress_struct* cinfo_; }; } // namespace -bool JPEGCodecRobustSlow::Decode(const unsigned char* input, size_t input_size, +bool JPEGCodecRobustSlow::Decode(const unsigned char* input, + size_t input_size, ColorFormat format, - std::vector<unsigned char>* output, int* w, + std::vector<unsigned char>* output, + int* w, int* h) { jpeg_decompress_struct cinfo; DecompressDestroyer destroyer;
diff --git a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h similarity index 76% rename from ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h rename to ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h index 08ca8b07..a6543cf 100644 --- a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h +++ b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_GFX_CHROMEOS_CODEC_JPEG_CODEC_ROBUST_SLOW_H_ -#define UI_GFX_CHROMEOS_CODEC_JPEG_CODEC_ROBUST_SLOW_H_ +#ifndef UI_GFX_CODEC_CHROMEOS_JPEG_CODEC_ROBUST_SLOW_H_ +#define UI_GFX_CODEC_CHROMEOS_JPEG_CODEC_ROBUST_SLOW_H_ #include <stddef.h> #include <vector> -#include "ui/gfx/gfx_export.h" +#include "ui/gfx/codec/codec_export.h" class SkBitmap; @@ -18,7 +18,7 @@ // which has an inconvenient interface for callers. This is only used for // servicing ChromeUtilityMsg_RobustJPEGDecodeImage and is currently unique // to Chrome OS. -class GFX_EXPORT JPEGCodecRobustSlow { +class CODEC_EXPORT JPEGCodecRobustSlow { public: enum ColorFormat { // 3 bytes per pixel (packed), in RGB order regardless of endianness. @@ -41,9 +41,12 @@ // decoded data will be placed in *output with the dimensions in *w and *h // on success (returns true). This data will be written in the'format' // format. On failure, the values of these output variables is undefined. - static bool Decode(const unsigned char* input, size_t input_size, - ColorFormat format, std::vector<unsigned char>* output, - int* w, int* h); + static bool Decode(const unsigned char* input, + size_t input_size, + ColorFormat format, + std::vector<unsigned char>* output, + int* w, + int* h); // Decodes the JPEG data contained in input of length input_size. If // successful, a SkBitmap is created and returned. It is up to the caller @@ -53,4 +56,4 @@ } // namespace gfx -#endif // UI_GFX_CHROMEOS_CODEC_JPEG_CODEC_ROBUST_SLOW_H_ +#endif // UI_GFX_CODEC_CHROMEOS_JPEG_CODEC_ROBUST_SLOW_H_
diff --git a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow_unittest.cc b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc similarity index 87% rename from ui/gfx/chromeos/codec/jpeg_codec_robust_slow_unittest.cc rename to ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc index 35e53ea..5304ab3 100644 --- a/ui/gfx/chromeos/codec/jpeg_codec_robust_slow_unittest.cc +++ b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow_unittest.cc
@@ -7,7 +7,7 @@ #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h" +#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h" namespace { @@ -93,16 +93,12 @@ TEST(JPEGCodecRobustSlow, InvalidRead) { std::vector<unsigned char> output; int outw, outh; - ASSERT_TRUE( - JPEGCodecRobustSlow::Decode(kTopSitesMigrationTestImage, - arraysize(kTopSitesMigrationTestImage), - JPEGCodecRobustSlow::FORMAT_RGB, &output, - &outw, &outh)); - ASSERT_TRUE( - JPEGCodecRobustSlow::Decode(kTopSitesMigrationTestImage, - arraysize(kTopSitesMigrationTestImage), - JPEGCodecRobustSlow::FORMAT_RGBA, &output, - &outw, &outh)); + ASSERT_TRUE(JPEGCodecRobustSlow::Decode( + kTopSitesMigrationTestImage, arraysize(kTopSitesMigrationTestImage), + JPEGCodecRobustSlow::FORMAT_RGB, &output, &outw, &outh)); + ASSERT_TRUE(JPEGCodecRobustSlow::Decode( + kTopSitesMigrationTestImage, arraysize(kTopSitesMigrationTestImage), + JPEGCodecRobustSlow::FORMAT_RGBA, &output, &outw, &outh)); } } // namespace gfx
diff --git a/ui/gfx/codec/codec_export.h b/ui/gfx/codec/codec_export.h new file mode 100644 index 0000000..c56a070f --- /dev/null +++ b/ui/gfx/codec/codec_export.h
@@ -0,0 +1,29 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_CODEC_CODEC_EXPORT_H_ +#define UI_GFX_CODEC_CODEC_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(CODEC_IMPLEMENTATION) +#define CODEC_EXPORT __declspec(dllexport) +#else +#define CODEC_EXPORT __declspec(dllimport) +#endif // defined(CODEC_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(CODEC_IMPLEMENTATION) +#define CODEC_EXPORT __attribute__((visibility("default"))) +#else +#define CODEC_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define CODEC_EXPORT +#endif + +#endif // UI_GFX_CODEC_CODEC_EXPORT_H_
diff --git a/ui/gfx/codec/jpeg_codec.h b/ui/gfx/codec/jpeg_codec.h index 3cc510b..5d10be5 100644 --- a/ui/gfx/codec/jpeg_codec.h +++ b/ui/gfx/codec/jpeg_codec.h
@@ -10,7 +10,7 @@ #include <memory> #include <vector> -#include "ui/gfx/gfx_export.h" +#include "ui/gfx/codec/codec_export.h" class SkBitmap; @@ -20,7 +20,7 @@ // which has an inconvenient interface for callers. This is only used for UI // elements, WebKit has its own more complicated JPEG decoder which handles, // among other things, partially downloaded data. -class GFX_EXPORT JPEGCodec { +class CODEC_EXPORT JPEGCodec { public: enum ColorFormat { // 3 bytes per pixel (packed), in RGB order regardless of endianness.
diff --git a/ui/gfx/codec/png_codec.h b/ui/gfx/codec/png_codec.h index ba8c815..bcc30e75 100644 --- a/ui/gfx/codec/png_codec.h +++ b/ui/gfx/codec/png_codec.h
@@ -11,7 +11,7 @@ #include <vector> #include "base/macros.h" -#include "ui/gfx/gfx_export.h" +#include "ui/gfx/codec/codec_export.h" class SkBitmap; @@ -25,7 +25,7 @@ // isn't as robust as would be required for a browser (see Decode() for more). // WebKit has its own more complicated PNG decoder which handles, among other // things, partially downloaded data. -class GFX_EXPORT PNGCodec { +class CODEC_EXPORT PNGCodec { public: enum ColorFormat { // 3 bytes per pixel (packed), in RGB order regardless of endianness. @@ -47,7 +47,7 @@ }; // Represents a comment in the tEXt ancillary chunk of the png. - struct GFX_EXPORT Comment { + struct CODEC_EXPORT Comment { Comment(const std::string& k, const std::string& t); ~Comment();
diff --git a/ui/gfx/codec/skia_image_encoder_adapter.h b/ui/gfx/codec/skia_image_encoder_adapter.h index f878969..f231a494 100644 --- a/ui/gfx/codec/skia_image_encoder_adapter.h +++ b/ui/gfx/codec/skia_image_encoder_adapter.h
@@ -6,7 +6,7 @@ #define UI_GFX_CODEC_SKIA_IMAGE_ENCODER_ADAPTER_H #include "third_party/skia/include/core/SkEncodedImageFormat.h" -#include "ui/gfx/gfx_export.h" +#include "ui/gfx/codec/codec_export.h" class SkWStream; class SkPixmap; @@ -15,10 +15,10 @@ // Matches signature of Skia's SkEncodeImage, but makes use of Chromium's // encoders. -GFX_EXPORT bool EncodeSkiaImage(SkWStream* dst, - const SkPixmap& pixmap, - SkEncodedImageFormat format, - int quality); +CODEC_EXPORT bool EncodeSkiaImage(SkWStream* dst, + const SkPixmap& pixmap, + SkEncodedImageFormat format, + int quality); } // namespace gfx
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc index d32ddc3..b90b8c9 100644 --- a/ui/gfx/color_space.cc +++ b/ui/gfx/color_space.cc
@@ -283,6 +283,13 @@ transfer_ == TransferID::IEC61966_2_1_HDR; } +bool ColorSpace::FullRangeEncodedValues() const { + return transfer_ == TransferID::LINEAR_HDR || + transfer_ == TransferID::IEC61966_2_1_HDR || + transfer_ == TransferID::BT1361_ECG || + transfer_ == TransferID::IEC61966_2_4; +} + bool ColorSpace::operator!=(const ColorSpace& other) const { return !(*this == other); }
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h index 8a05ba0..0331be7 100644 --- a/ui/gfx/color_space.h +++ b/ui/gfx/color_space.h
@@ -155,7 +155,10 @@ bool operator<(const ColorSpace& other) const; std::string ToString() const; + // Returns true if the decoded values can be outside of the 0.0-1.0 range. bool IsHDR() const; + // Returns true if the encoded values can be outside of the 0.0-1.0 range. + bool FullRangeEncodedValues() const; // Return this color space with any range adjust or YUV to RGB conversion // stripped off.
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc index 5d740f2..9bd31eb 100644 --- a/ui/gl/init/gl_factory_ozone.cc +++ b/ui/gl/init/gl_factory_ozone.cc
@@ -18,7 +18,7 @@ namespace init { std::vector<GLImplementation> GetAllowedGLImplementations() { - ui::OzonePlatform::InitializeForGPU(); + DCHECK(GetSurfaceFactoryOzone()); return GetSurfaceFactoryOzone()->GetAllowedGLImplementations(); }
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc index 79709c4..9034918f 100644 --- a/ui/gl/test/gl_image_test_support.cc +++ b/ui/gl/test/gl_image_test_support.cc
@@ -12,12 +12,19 @@ #if defined(USE_OZONE) #include "base/run_loop.h" +#include "ui/ozone/public/ozone_platform.h" #endif namespace gl { // static void GLImageTestSupport::InitializeGL() { +#if defined(USE_OZONE) + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForGPU(params); +#endif + std::vector<GLImplementation> allowed_impls = init::GetAllowedGLImplementations(); DCHECK(!allowed_impls.empty());
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc index 272e0fd7..dcfd5cae 100644 --- a/ui/gl/test/gl_surface_test_support.cc +++ b/ui/gl/test/gl_surface_test_support.cc
@@ -32,6 +32,13 @@ #if defined(USE_X11) XInitThreads(); #endif + +#if defined(USE_OZONE) + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForGPU(params); +#endif + ui::test::EnableTestConfigForPlatformWindows(); bool use_software_gl = true; @@ -88,17 +95,21 @@ // static void GLSurfaceTestSupport::InitializeOneOffWithMockBindings() { #if defined(USE_OZONE) - // This function skips where Ozone is otherwise initialized. - ui::OzonePlatform::InitializeForGPU(); + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForGPU(params); #endif + InitializeOneOffImplementation(kGLImplementationMockGL, false); } void GLSurfaceTestSupport::InitializeOneOffWithStubBindings() { #if defined(USE_OZONE) - // This function skips where Ozone is otherwise initialized. - ui::OzonePlatform::InitializeForGPU(); + ui::OzonePlatform::InitParams params; + params.single_process = true; + ui::OzonePlatform::InitializeForGPU(params); #endif + InitializeOneOffImplementation(kGLImplementationStubGL, false); }
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc index b723460a..04caf81 100644 --- a/ui/ozone/public/ozone_platform.cc +++ b/ui/ozone/public/ozone_platform.cc
@@ -51,12 +51,6 @@ } // static -void OzonePlatform::InitializeForGPU() { - const InitParams params; - OzonePlatform::InitializeForGPU(params); -} - -// static void OzonePlatform::InitializeForGPU(const InitParams& args) { EnsureInstance(); if (g_platform_initialized_gpu)
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h index f1995c1..ad45363 100644 --- a/ui/ozone/public/ozone_platform.h +++ b/ui/ozone/public/ozone_platform.h
@@ -89,10 +89,6 @@ // InitalizeForUI. static void InitializeForUI(const InitParams& args); - // Initializes the subsystems/resources necessary for rendering (i.e. GPU). - // TODO(rjkroege): Remove deprecated entry point (http://crbug.com/620934) - static void InitializeForGPU(); - // Initializes the subsystems for rendering but with additional properties // provided by |args| as with InitalizeForUI. static void InitializeForGPU(const InitParams& args);
diff --git a/ui/webui/resources/js/compiled_resources.gyp b/ui/webui/resources/js/compiled_resources.gyp index d679f4c..a5764736 100644 --- a/ui/webui/resources/js/compiled_resources.gyp +++ b/ui/webui/resources/js/compiled_resources.gyp
@@ -23,15 +23,13 @@ 'target_name': 'i18n_template_no_process', 'variables': { 'depends': ['compiled_resources.gyp:load_time_data'], - 'externs': ['../../../../third_party/closure_compiler/externs/pending_compiler_externs.js'], }, 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'], }, { 'target_name': 'i18n_template', 'variables': { - 'depends': ['compiled_resources.gyp:load_time_data'], - 'externs': ['../../../../third_party/closure_compiler/externs/pending_compiler_externs.js'], + 'depends': ['compiled_resources.gyp:i18n_template_no_process'], }, 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'], },
diff --git a/ui/webui/resources/js/compiled_resources2.gyp b/ui/webui/resources/js/compiled_resources2.gyp index e7849f77..1316c15 100644 --- a/ui/webui/resources/js/compiled_resources2.gyp +++ b/ui/webui/resources/js/compiled_resources2.gyp
@@ -36,17 +36,13 @@ 'target_name': 'i18n_template_no_process', 'dependencies': [ 'load_time_data', - '<(EXTERNS_GYP):pending_compiler_externs', ], 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], }, { 'target_name': 'i18n_template', 'dependencies': [ - 'load_time_data', - # Ideally, <include> would automatically import externs as well, but - # it current doesn't and that sounds hard. Let's just kill <include>. - '<(EXTERNS_GYP):pending_compiler_externs', + 'i18n_template_no_process', ], 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], },