diff --git a/DEPS b/DEPS index 61965c4b..281e840 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'ba69da40dc9aade163504a99f088252c711b4bf4', + 'v8_revision': 'c59a968ba3e44a7c7bd7359efcfb636a373e9339', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -202,7 +202,7 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '72eda82d069da578af04e5c4e8e411ae006b6a18', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'ca7121e53f7794a60ac2948c34c224ee921a8910', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc index f2382820..e781b23 100644 --- a/ash/wm/lock_state_controller.cc +++ b/ash/wm/lock_state_controller.cc
@@ -496,9 +496,8 @@ base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs); - // Increase lock timeout for "daisy", see http://crbug.com/350628. (The boards - // "daisy_spring" and "daisy_skate" are fast thus using an exact string match - // instead of base::StartsWith().) + // TODO(derat): Remove this scaling after October 2017 when daisy (Samsung + // Chromebook XE303) is unsupported. if (base::SysInfo::GetStrippedReleaseBoard() == "daisy") timeout *= 2; lock_fail_timer_.Start(FROM_HERE, timeout, this,
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc index 7780df528..7c2a6c2 100644 --- a/base/metrics/histogram.cc +++ b/base/metrics/histogram.cc
@@ -39,6 +39,15 @@ namespace { +// A constant to be stored in the dummy field and later verified. This could +// be either 32 or 64 bit but clang won't truncate the value without an error. +// TODO(bcwhite): Remove this once crbug/736675 is fixed. +#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) +constexpr uintptr_t kDummyValue = 0xFEEDC0DEDEADBEEF; +#else +constexpr uintptr_t kDummyValue = 0xDEADBEEF; +#endif + // TODO(asvitkine): Remove this after crbug/736675. char g_last_logged_histogram_name[256] = {0}; @@ -582,7 +591,7 @@ // Temporary for https://crbug.com/736675. base::debug::ScopedCrashKey crash_key("bad_histogram", debug_string); #endif - CHECK(false) << debug_string; + // CHECK(false) << debug_string; debug::Alias(&bad_fields); return false; } @@ -602,7 +611,7 @@ Sample minimum, Sample maximum, const BucketRanges* ranges) - : HistogramBase(name) { + : HistogramBase(name), dummy_(kDummyValue) { // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. CHECK(ranges) << name << ": " << minimum << "-" << maximum; unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); @@ -617,7 +626,7 @@ const DelayedPersistentAllocation& logged_counts, HistogramSamples::Metadata* meta, HistogramSamples::Metadata* logged_meta) - : HistogramBase(name) { + : HistogramBase(name), dummy_(kDummyValue) { // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. CHECK(ranges) << name << ": " << minimum << "-" << maximum; unlogged_samples_.reset(
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h index f0aa7296..9515d0c 100644 --- a/base/metrics/histogram.h +++ b/base/metrics/histogram.h
@@ -311,6 +311,13 @@ int64_t* sum, ListValue* buckets) const override; + // This is a dummy field placed where corruption is frequently seen on + // current Android builds. The hope is that it will mitigate the problem + // sufficiently to continue with the M61 beta branch while investigation + // into the true problem continues. + // TODO(bcwhite): Remove this once crbug/736675 is fixed. + const uintptr_t dummy_; + // Samples that have not yet been logged with SnapshotDelta(). std::unique_ptr<SampleVectorBase> unlogged_samples_;
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc index b38433b2..260fde9 100644 --- a/base/metrics/histogram_snapshot_manager.cc +++ b/base/metrics/histogram_snapshot_manager.cc
@@ -45,13 +45,15 @@ } void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) { - histogram->ValidateHistogramContents(true, 0); + if (!histogram->ValidateHistogramContents(true, 0)) + return; PrepareSamples(histogram, histogram->SnapshotDelta()); } void HistogramSnapshotManager::PrepareFinalDelta( const HistogramBase* histogram) { - histogram->ValidateHistogramContents(true, 0); + if (!histogram->ValidateHistogramContents(true, 0)) + return; PrepareSamples(histogram, histogram->SnapshotFinalDelta()); }
diff --git a/base/sys_info.h b/base/sys_info.h index 5f68df4..d435d58 100644 --- a/base/sys_info.h +++ b/base/sys_info.h
@@ -116,17 +116,25 @@ static bool GetLsbReleaseValue(const std::string& key, std::string* value); // Convenience function for GetLsbReleaseValue("CHROMEOS_RELEASE_BOARD",...). - // Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set. Otherwise returns - // the full name of the board. WARNING: the returned value often differs in - // developer built system compared to devices that use the official version. - // E.g. for developer built version, the function could return 'glimmer' while - // for officially used versions it would be like 'glimmer-signed-mp-v4keys'. - // Use GetStrippedReleaseBoard() function if you need only the short name of - // the board (would be 'glimmer' in the case described above). + // Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set. Otherwise, returns + // the full name of the board. Note that the returned value often differs + // between developers' systems and devices that use official builds. E.g. for + // a developer-built image, the function could return 'glimmer', while in an + // official build, it may be something like 'glimmer-signed-mp-v4keys'. + // + // NOTE: Strings returned by this function should be treated as opaque values + // within Chrome (e.g. for reporting metrics elsewhere). If you need to make + // Chrome behave differently for different Chrome OS devices, either directly + // check for the hardware feature that you care about (preferred) or add a + // command-line flag to Chrome and pass it from session_manager (based on + // whether a USE flag is set or not). See https://goo.gl/BbBkzg for more + // details. static std::string GetLsbReleaseBoard(); + // DEPRECATED: Please see GetLsbReleaseBoard's comment. // Convenience function for GetLsbReleaseBoard() removing trailing "-signed-*" // if present. Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set. + // TODO(derat): Delete this after October 2017. static std::string GetStrippedReleaseBoard(); // Returns the creation time of /etc/lsb-release. (Used to get the date and
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py index 0e37159d..2f695f4 100644 --- a/build/android/apk_operations.py +++ b/build/android/apk_operations.py
@@ -3,7 +3,7 @@ # found in the LICENSE file. import argparse -import imp +import json import logging import os import pipes @@ -18,44 +18,26 @@ from devil.android.sdk import adb_wrapper from devil.utils import run_tests_helper +from incremental_install import installer from pylib import constants -def _InstallApk(install_incremental, inc_install_script, devices_obj, - apk_to_install): - if install_incremental: - helper = apk_helper.ApkHelper(apk_to_install) - try: - install_wrapper = imp.load_source('install_wrapper', inc_install_script) - except IOError: - raise Exception('Incremental install script not found: %s\n' % - inc_install_script) - params = install_wrapper.GetInstallParameters() - - def install_incremental_apk(device): - from incremental_install import installer - installer.Install(device, helper, split_globs=params['splits'], - native_libs=params['native_libs'], - dex_files=params['dex_files'], permissions=None) - devices_obj.pMap(install_incremental_apk) - else: - # Install the regular apk on devices. - def install(device): - device.Install(apk_to_install) - devices_obj.pMap(install) +def _InstallApk(apk, install_dict, devices_obj): + def install(device): + if install_dict: + installer.Install(device, install_dict, apk=apk) + else: + device.Install(apk) + devices_obj.pMap(install) -def _UninstallApk(install_incremental, devices_obj, apk_package): - if install_incremental: - def uninstall_incremental_apk(device): - from incremental_install import installer +def _UninstallApk(install_dict, devices_obj, apk_package): + def uninstall(device): + if install_dict: installer.Uninstall(device, apk_package) - devices_obj.pMap(uninstall_incremental_apk) - else: - # Uninstall the regular apk on devices. - def uninstall(device): + else: device.Uninstall(apk_package) - devices_obj.pMap(uninstall) + devices_obj.pMap(uninstall) def _LaunchUrl(devices_obj, input_args, device_args_file, url, apk_package): @@ -160,8 +142,60 @@ return os.path.join(constants.GetOutDirectory(), file_name) -def Run(output_directory, apk_path, inc_apk_path, inc_install_script, - command_line_flags_file): +def _SelectApk(apk_path, incremental_install_json_path, parser, args): + if apk_path and not os.path.exists(apk_path): + apk_path = None + if (incremental_install_json_path and + not os.path.exists(incremental_install_json_path)): + incremental_install_json_path = None + + if args.incremental and args.non_incremental: + parser.error('--incremental and --non-incremental cannot both be used.') + elif args.non_incremental: + if not apk_path: + parser.error('Apk has not been built.') + incremental_install_json_path = None + elif args.incremental: + if not incremental_install_json_path: + parser.error('Incremental apk has not been built.') + apk_path = None + + if args.command in ('install', 'run'): + if apk_path and incremental_install_json_path: + parser.error('Both incremental and non-incremental apks exist, please ' + 'use --incremental or --non-incremental to select one.') + elif apk_path: + logging.info('Using the non-incremental apk.') + elif incremental_install_json_path: + logging.info('Using the incremental apk.') + else: + parser.error('Neither incremental nor non-incremental apk is built.') + return apk_path, incremental_install_json_path + + +def _LoadDeviceCaches(devices): + for d in devices: + cache_path = _DeviceCachePath(d) + if os.path.exists(cache_path): + logging.info('Using device cache: %s', cache_path) + with open(cache_path) as f: + d.LoadCacheData(f.read()) + # Delete the cached file so that any exceptions cause it to be cleared. + os.unlink(cache_path) + else: + logging.info('No cache present for device: %s', d) + + +def _SaveDeviceCaches(devices): + for d in devices: + cache_path = _DeviceCachePath(d) + with open(cache_path, 'w') as f: + f.write(d.DumpCacheData()) + logging.info('Wrote device cache: %s', cache_path) + + +def Run(output_directory, apk_path, incremental_install_json_path, + command_line_flags_file): constants.SetOutputDirectory(output_directory) parser = argparse.ArgumentParser() @@ -229,79 +263,33 @@ if len(devices) > 1 and not args.all: raise Exception(_GenerateMissingAllFlagMessage(devices, devices_obj)) - if args.incremental and args.non_incremental: - raise Exception('--incremental and --non-incremental cannot be set at the ' - 'same time.') - install_incremental = False - active_apk = None - apk_package = None apk_name = os.path.basename(apk_path) - if apk_path and not os.path.exists(apk_path): - apk_path = None + apk_path, incremental_install_json_path = _SelectApk( + apk_path, incremental_install_json_path, parser, args) + install_dict = None - if args.non_incremental: - if apk_path: - active_apk = apk_path - logging.info('Use the non-incremental apk.') - else: - raise Exception("No regular apk is available.") + if incremental_install_json_path: + with open(incremental_install_json_path) as f: + install_dict = json.load(f) + apk = apk_helper.ToHelper( + os.path.join(output_directory, install_dict['apk_path'])) + else: + apk = apk_helper.ToHelper(apk_path) - if inc_apk_path and not os.path.exists(inc_apk_path): - inc_apk_path = None - - if args.incremental: - if inc_apk_path: - active_apk = inc_apk_path - install_incremental = True - logging.info('Use the incremental apk.') - else: - raise Exception("No incremental apk is available.") - - if not args.incremental and not args.non_incremental and command in { - 'install', 'run'}: - if apk_path and inc_apk_path: - raise Exception('Both incremental and non-incremental apks exist, please ' - 'use --incremental or --non-incremental to select one.') - if not apk_path and not inc_apk_path: - raise Exception('Neither incremental nor non-incremental apk is ' - 'available.') - if apk_path: - active_apk = apk_path - logging.info('Use the non-incremental apk.') - else: - active_apk = inc_apk_path - install_incremental = True - logging.info('Use the incremental apk.') - - if apk_path is not None: - apk_package = apk_helper.GetPackageName(apk_path) - elif inc_apk_path is not None: - apk_package = apk_helper.GetPackageName(inc_apk_path) + apk_package = apk.GetPackageName() if use_cache: - for d in devices: - cache_path = _DeviceCachePath(d) - if os.path.exists(cache_path): - logging.info('Using device cache: %s', cache_path) - with open(cache_path) as f: - d.LoadCacheData(f.read()) - # Delete the cached file so that any exceptions cause it to be cleared. - os.unlink(cache_path) - else: - logging.info('No cache present for device: %s', d) + _LoadDeviceCaches(devices) if command == 'install': - _InstallApk(install_incremental, inc_install_script, devices_obj, - active_apk) + _InstallApk(apk, install_dict, devices_obj) elif command == 'uninstall': - _UninstallApk(install_incremental, devices_obj, apk_package) + _UninstallApk(install_dict, devices_obj, apk_package) elif command == 'launch': _LaunchUrl(devices_obj, args.args, command_line_flags_file, args.url, apk_package) elif command == 'run': - _InstallApk(install_incremental, inc_install_script, devices_obj, - active_apk) - devices_obj.pFinish(None) + _InstallApk(apk, install_dict, devices_obj) _LaunchUrl(devices_obj, args.args, command_line_flags_file, args.url, apk_package) elif command == 'stop': @@ -336,13 +324,6 @@ flags = [adb_path, '-s', devices[0].adb.GetDeviceSerial(), 'logcat'] os.execv(adb_path, flags) - # Wait for all threads to finish. - devices_obj.pFinish(None) - # Save back to the cache. if use_cache: - for d in devices: - cache_path = _DeviceCachePath(d) - with open(cache_path, 'w') as f: - f.write(d.DumpCacheData()) - logging.info('Wrote device cache: %s', cache_path) + _SaveDeviceCaches(devices)
diff --git a/build/android/gyp/create_apk_operations_script.py b/build/android/gyp/create_apk_operations_script.py index 4d426f42..dddeb7a 100755 --- a/build/android/gyp/create_apk_operations_script.py +++ b/build/android/gyp/create_apk_operations_script.py
@@ -24,10 +24,9 @@ script_directory, p)) sys.path.append(resolve(${APK_OPERATIONS_DIR})) import apk_operations - apk_operations.Run(output_directory=resolve(${OUTPUT_DIR}), - apk_path=resolve(${APK_PATH}), - inc_apk_path=resolve(${INC_APK_PATH}), - inc_install_script=resolve(${INC_INSTALL_SCRIPT}), + apk_operations.Run(resolve(${OUTPUT_DIR}), + resolve(${APK_PATH}), + resolve(${INC_JSON_PATH}), command_line_flags_file=${FLAGS_FILE}) @@ -41,8 +40,7 @@ parser.add_argument('--script-output-path', help='Output path for executable script.') parser.add_argument('--apk-path') - parser.add_argument('--incremental-apk-path') - parser.add_argument('--incremental-install-script') + parser.add_argument('--incremental-install-json-path') parser.add_argument('--command-line-flags-file') args = parser.parse_args(args) @@ -59,8 +57,7 @@ 'APK_OPERATIONS_DIR': repr(apk_operations_dir), 'OUTPUT_DIR': repr(relativize('.')), 'APK_PATH': repr(relativize(args.apk_path)), - 'INC_APK_PATH': repr(relativize(args.incremental_apk_path)), - 'INC_INSTALL_SCRIPT': repr(relativize(args.incremental_install_script)), + 'INC_JSON_PATH': repr(relativize(args.incremental_install_json_path)), 'FLAGS_FILE': repr(args.command_line_flags_file), } script.write(SCRIPT_TEMPLATE.substitute(script_dict))
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 63a8ee8..f3617ae 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -312,9 +312,9 @@ parser.add_option('--apk-path', help='Path to the target\'s apk output.') parser.add_option('--incremental-apk-path', help="Path to the target's incremental apk output.") - parser.add_option('--incremental-install-script-path', + parser.add_option('--incremental-install-json-path', help="Path to the target's generated incremental install " - "script.") + "json.") parser.add_option('--tested-apk-config', help='Path to the build config of the tested apk (for an instrumentation ' @@ -472,8 +472,8 @@ if options.type == 'android_apk': deps_info['apk_path'] = options.apk_path deps_info['incremental_apk_path'] = options.incremental_apk_path - deps_info['incremental_install_script_path'] = ( - options.incremental_install_script_path) + deps_info['incremental_install_json_path'] = ( + options.incremental_install_json_path) deps_info['enable_relocation_packing'] = options.enable_relocation_packing if options.type in ('java_binary', 'java_library', 'android_apk', 'dist_jar'):
diff --git a/build/android/incremental_install/create_install_script.py b/build/android/incremental_install/create_install_script.py deleted file mode 100755 index 09004da..0000000 --- a/build/android/incremental_install/create_install_script.py +++ /dev/null
@@ -1,158 +0,0 @@ -#!/usr/bin/env python - -# 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. - -"""Creates a script to run an "_incremental" .apk.""" - -import argparse -import os -import pprint -import sys - -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir)) -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'gyp')) - -from pylib.constants import host_paths -from util import build_utils - - -SCRIPT_TEMPLATE = """\ -#!/usr/bin/env python -# -# This file was generated by: -# //build/android/incremental_install/create_install_script.py - -import os -import subprocess -import sys - - -def _ResolvePath(path): - script_directory = os.path.dirname(__file__) - return os.path.abspath(os.path.join(script_directory, path)) - - -# Exported to allow test runner to be able to install incremental apks. -def GetInstallParameters(): - apk_path = {apk_path} - dex_files = {dex_files} - dont_even_try = {dont_even_try} - native_libs = {native_libs} - show_proguard_warning = {show_proguard_warning} - splits = {splits} - - return dict(apk_path=_ResolvePath(apk_path), - dex_files=[_ResolvePath(p) for p in dex_files], - dont_even_try=dont_even_try, - native_libs=[_ResolvePath(p) for p in native_libs], - show_proguard_warning=show_proguard_warning, - splits=[_ResolvePath(p) for p in splits]) - - -def main(): - output_directory = {output_directory} - cmd_path = {cmd_path} - params = GetInstallParameters() - cmd_args = [ - _ResolvePath(cmd_path), - '--output-directory', _ResolvePath(output_directory), - ] - for native_lib in params['native_libs']: - cmd_args.extend(('--native_lib', native_lib)) - for dex_path in params['dex_files']: - cmd_args.extend(('--dex-file', dex_path)) - for split in params['splits']: - cmd_args.extend(('--split', split)) - cmd_args.append(params['apk_path']) - if params['dont_even_try']: - cmd_args.extend(('--dont-even-try', params['dont_even_try'])) - if params['show_proguard_warning']: - cmd_args.append('--show-proguard-warning') - return subprocess.call(cmd_args + sys.argv[1:]) - -if __name__ == '__main__': - sys.exit(main()) -""" - - -def _ParseArgs(args): - args = build_utils.ExpandFileArgs(args) - parser = argparse.ArgumentParser() - build_utils.AddDepfileOption(parser) - parser.add_argument('--script-output-path', - help='Output path for executable script.', - required=True) - parser.add_argument('--output-directory', - help='Path to the root build directory.', - default='.') - parser.add_argument('--apk-path', - help='Path to the .apk to install.', - required=True) - parser.add_argument('--split', - action='append', - dest='splits', - default=[], - help='A glob matching the apk splits. ' - 'Can be specified multiple times.') - parser.add_argument('--native-libs', - action='append', - default=[], - help='GYP-list of paths to native libraries. Can be ' - 'repeated.') - parser.add_argument('--dex-file', - action='append', - default=[], - dest='dex_files', - help='List of dex files to include.') - parser.add_argument('--dex-file-list', - help='GYP-list of dex files.') - parser.add_argument('--show-proguard-warning', - action='store_true', - default=False, - help='Print a warning about proguard being disabled') - parser.add_argument('--dont-even-try', - help='Prints this message and exits.') - - options = parser.parse_args(args) - options.dex_files += build_utils.ParseGnList(options.dex_file_list) - all_libs = [] - for gyp_list in options.native_libs: - all_libs.extend(build_utils.ParseGnList(gyp_list)) - options.native_libs = all_libs - return options - - -def main(args): - options = _ParseArgs(args) - - def relativize(path): - script_dir = os.path.dirname(options.script_output_path) - return path and os.path.relpath(path, script_dir) - - installer_path = os.path.join(host_paths.DIR_SOURCE_ROOT, 'build', 'android', - 'incremental_install', 'installer.py') - pformat = pprint.pformat - template_args = { - 'cmd_path': pformat(relativize(installer_path)), - 'apk_path': pformat(relativize(options.apk_path)), - 'output_directory': pformat(relativize(options.output_directory)), - 'native_libs': pformat([relativize(p) for p in options.native_libs]), - 'dex_files': pformat([relativize(p) for p in options.dex_files]), - 'dont_even_try': pformat(options.dont_even_try), - 'show_proguard_warning': pformat(options.show_proguard_warning), - 'splits': pformat([relativize(p) for p in options.splits]), - } - - with open(options.script_output_path, 'w') as script: - script.write(SCRIPT_TEMPLATE.format(**template_args)) - - os.chmod(options.script_output_path, 0750) - - if options.depfile: - build_utils.WriteDepfile(options.depfile, options.script_output_path) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:]))
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py index 54abf76..92f86af 100755 --- a/build/android/incremental_install/installer.py +++ b/build/android/incremental_install/installer.py
@@ -8,6 +8,7 @@ import argparse import glob +import json import logging import os import posixpath @@ -83,31 +84,43 @@ logging.info('Uninstall took %s seconds.', main_timer.GetDelta()) -def Install(device, apk, split_globs=None, native_libs=None, dex_files=None, - enable_device_cache=False, use_concurrency=True, - show_proguard_warning=False, permissions=(), - allow_downgrade=True): +def Install(device, install_json, apk=None, enable_device_cache=False, + use_concurrency=True, permissions=()): """Installs the given incremental apk and all required supporting files. Args: - device: A DeviceUtils instance. - apk: The path to the apk, or an ApkHelper instance. - split_globs: Glob patterns for any required apk splits (optional). - native_libs: List of app's native libraries (optional). - dex_files: List of .dex.jar files that comprise the app's Dalvik code. + device: A DeviceUtils instance (to install to). + install_json: Path to .json file or already parsed .json object. + apk: An existing ApkHelper instance for the apk (optional). enable_device_cache: Whether to enable on-device caching of checksums. use_concurrency: Whether to speed things up using multiple threads. - show_proguard_warning: Whether to print a warning about Proguard not being - enabled after installing. permissions: A list of the permissions to grant, or None to grant all non-blacklisted permissions in the manifest. """ + if isinstance(install_json, basestring): + with open(install_json) as f: + install_dict = json.load(f) + else: + install_dict = install_json + + if install_dict.get('dont_even_try'): + raise Exception(install_dict['dont_even_try']) + main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() - apk = apk_helper.ToHelper(apk) + def fix_path(p): + return os.path.normpath(os.path.join(constants.GetOutDirectory(), p)) + + if not apk: + apk = apk_helper.ToHelper(fix_path(install_dict['apk_path'])) + split_globs = [fix_path(p) for p in install_dict['split_globs']] + native_libs = [fix_path(p) for p in install_dict['native_libs']] + dex_files = [fix_path(p) for p in install_dict['dex_files']] + show_proguard_warning = install_dict.get('show_proguard_warning') + apk_package = apk.GetPackageName() device_incremental_dir = _GetDeviceIncrementalDir(apk_package) @@ -119,11 +132,9 @@ for split_glob in split_globs: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk(apk, splits, reinstall=True, - allow_cached_props=True, permissions=permissions, - allow_downgrade=allow_downgrade) + allow_cached_props=True, permissions=permissions) else: - device.Install(apk, reinstall=True, permissions=permissions, - allow_downgrade=allow_downgrade) + device.Install(apk, reinstall=True, permissions=permissions) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). @@ -227,23 +238,8 @@ def main(): parser = argparse.ArgumentParser() - parser.add_argument('apk_path', - help='The path to the APK to install.') - parser.add_argument('--split', - action='append', - dest='splits', - help='A glob matching the apk splits. ' - 'Can be specified multiple times.') - parser.add_argument('--native_lib', - dest='native_libs', - help='Path to native library (repeatable)', - action='append', - default=[]) - parser.add_argument('--dex-file', - dest='dex_files', - help='Path to dex files (repeatable)', - action='append', - default=[]) + parser.add_argument('json_path', + help='The path to the generated incremental apk .json.') parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', @@ -263,38 +259,21 @@ dest='cache', help='Do not use cached information about what files are ' 'currently on the target device.') - parser.add_argument('--show-proguard-warning', - action='store_true', - default=False, - help='Print a warning about proguard being disabled') - parser.add_argument('--dont-even-try', - help='Prints this message and exits.') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') - parser.add_argument('--disable-downgrade', - action='store_false', - default=True, - dest='allow_downgrade', - help='Disable install of apk with lower version number' - 'than the version already on the device.') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) - constants.SetBuildType('Debug') if args.output_directory: constants.SetOutputDirectory(args.output_directory) devil_chromium.Initialize(output_directory=constants.GetOutDirectory()) - if args.dont_even_try: - logging.fatal(args.dont_even_try) - return 1 - # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils.HealthyDevices( @@ -302,15 +281,14 @@ default_retries=0, enable_device_files_cache=True)[0] - apk = apk_helper.ToHelper(args.apk_path) if args.uninstall: + with open(args.json_path) as f: + install_dict = json.load(f) + apk = apk_helper.ToHelper(install_dict['apk_path']) Uninstall(device, apk.GetPackageName(), enable_device_cache=args.cache) else: - Install(device, apk, split_globs=args.splits, native_libs=args.native_libs, - dex_files=args.dex_files, enable_device_cache=args.cache, - use_concurrency=args.threading, - show_proguard_warning=args.show_proguard_warning, - allow_downgrade=args.allow_downgrade) + Install(device, args.json_path, enable_device_cache=args.cache, + use_concurrency=args.threading) if __name__ == '__main__':
diff --git a/build/android/incremental_install/write_installer_json.py b/build/android/incremental_install/write_installer_json.py new file mode 100755 index 0000000..66ddd49d --- /dev/null +++ b/build/android/incremental_install/write_installer_json.py
@@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# 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. + +"""Writes a .json file with the per-apk details for an incremental install.""" + +import argparse +import json +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'gyp')) + +from util import build_utils + + +def _ParseArgs(args): + args = build_utils.ExpandFileArgs(args) + parser = argparse.ArgumentParser() + build_utils.AddDepfileOption(parser) + parser.add_argument('--output-path', + help='Output path for .json file.', + required=True) + parser.add_argument('--apk-path', + help='Path to .apk relative to output directory.', + required=True) + parser.add_argument('--split', + action='append', + dest='split_globs', + default=[], + help='A glob matching the apk splits. ' + 'Can be specified multiple times.') + parser.add_argument('--native-libs-list', + action='append', + default=[], + help='GN-list of paths to native libraries relative to ' + 'output directory. Can be repeated.') + parser.add_argument('--dex-file', + action='append', + default=[], + dest='dex_files', + help='.dex file to include relative to output directory. ' + 'Can be repeated') + parser.add_argument('--dex-file-list', + help='GN-list of dex paths relative to output directory.') + parser.add_argument('--show-proguard-warning', + action='store_true', + default=False, + help='Print a warning about proguard being disabled') + parser.add_argument('--dont-even-try', + help='Prints the given message and exits.') + + options = parser.parse_args(args) + options.dex_files += build_utils.ParseGnList(options.dex_file_list) + all_libs = [] + for gn_list in options.native_libs_list: + all_libs.extend(build_utils.ParseGnList(gn_list)) + options.native_libs_list = all_libs + return options + + +def main(args): + options = _ParseArgs(args) + + data = { + 'apk_path': options.apk_path, + 'native_libs': options.native_libs_list, + 'dex_files': options.dex_files, + 'dont_even_try': options.dont_even_try, + 'show_proguard_warning': options.show_proguard_warning, + 'split_globs': options.split_globs, + } + + with open(options.output_path, 'w') as f: + json.dump(data, f, indent=2, sort_keys=True) + + if options.depfile: + build_utils.WriteDepfile(options.depfile, options.output_path) + + +if __name__ == '__main__': + main(sys.argv[1:])
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py index 9e4e19a..bb1dbb9 100644 --- a/build/android/pylib/gtest/gtest_test_instance.py +++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -281,14 +281,14 @@ self._exe_dist_dir = exe_dist_dir incremental_part = '' - if args.test_apk_incremental_install_script: + if args.test_apk_incremental_install_json: incremental_part = '_incremental' apk_path = os.path.join( constants.GetOutDirectory(), '%s_apk' % self._suite, '%s-debug%s.apk' % (self._suite, incremental_part)) - self._test_apk_incremental_install_script = ( - args.test_apk_incremental_install_script) + self._test_apk_incremental_install_json = ( + args.test_apk_incremental_install_json) if not os.path.exists(apk_path): self._apk_helper = None else: @@ -423,8 +423,8 @@ return self._suite @property - def test_apk_incremental_install_script(self): - return self._test_apk_incremental_install_script + def test_apk_incremental_install_json(self): + return self._test_apk_incremental_install_json @property def total_external_shards(self):
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py index fc6a1a7..b6dd7c6 100644 --- a/build/android/pylib/instrumentation/instrumentation_test_instance.py +++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -445,11 +445,11 @@ self._additional_apks = [] self._apk_under_test = None - self._apk_under_test_incremental_install_script = None + self._apk_under_test_incremental_install_json = None self._package_info = None self._suite = None self._test_apk = None - self._test_apk_incremental_install_script = None + self._test_apk_incremental_install_json = None self._test_jar = None self._test_package = None self._junit3_runner_class = None @@ -536,12 +536,12 @@ self._test_apk = apk_helper.ToHelper(test_apk_path) - self._apk_under_test_incremental_install_script = ( - args.apk_under_test_incremental_install_script) - self._test_apk_incremental_install_script = ( - args.test_apk_incremental_install_script) + self._apk_under_test_incremental_install_json = ( + args.apk_under_test_incremental_install_json) + self._test_apk_incremental_install_json = ( + args.test_apk_incremental_install_json) - if self._test_apk_incremental_install_script: + if self._test_apk_incremental_install_json: assert self._suite.endswith('_incremental') self._suite = self._suite[:-len('_incremental')] @@ -700,8 +700,8 @@ return self._apk_under_test @property - def apk_under_test_incremental_install_script(self): - return self._apk_under_test_incremental_install_script + def apk_under_test_incremental_install_json(self): + return self._apk_under_test_incremental_install_json @property def coverage_directory(self): @@ -780,8 +780,8 @@ return self._test_apk @property - def test_apk_incremental_install_script(self): - return self._test_apk_incremental_install_script + def test_apk_incremental_install_json(self): + return self._test_apk_incremental_install_json @property def test_jar(self):
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py index 62ad71f5..4d0dfe0 100644 --- a/build/android/pylib/local/device/local_device_gtest_run.py +++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -14,6 +14,7 @@ from devil.android import device_temp_file from devil.android import ports from devil.utils import reraiser_thread +from incremental_install import installer from pylib import constants from pylib.base import base_test_result from pylib.gtest import gtest_test_instance @@ -106,8 +107,8 @@ def __init__(self, test_instance): self._activity = test_instance.activity self._apk_helper = test_instance.apk_helper - self._test_apk_incremental_install_script = ( - test_instance.test_apk_incremental_install_script) + self._test_apk_incremental_install_json = ( + test_instance.test_apk_incremental_install_json) self._package = test_instance.package self._runner = test_instance.runner self._permissions = test_instance.permissions @@ -121,9 +122,9 @@ 'chromium_tests_root') def Install(self, device): - if self._test_apk_incremental_install_script: - local_device_test_run.IncrementalInstall(device, self._apk_helper, - self._test_apk_incremental_install_script) + if self._test_apk_incremental_install_json: + installer.Install(device, self._test_apk_incremental_install_json, + apk=self._apk_helper) else: device.Install(self._apk_helper, reinstall=True, permissions=self._permissions)
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index 14d97b31..51611f2 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -19,6 +19,7 @@ from devil.android import flag_changer from devil.android.tools import system_app from devil.utils import reraiser_thread +from incremental_install import installer from pylib import valgrind_tools from pylib.android import logdog_logcat_monitor from pylib.base import base_test_result @@ -162,31 +163,30 @@ return lambda: crash_handler.RetryOnSystemCrash( install_helper_internal, dev) - def incremental_install_helper(apk, script): + def incremental_install_helper(apk, json_path): @trace_event.traced("apk_path") def incremental_install_helper_internal(d, apk_path=apk.path): # pylint: disable=unused-argument - local_device_test_run.IncrementalInstall( - d, apk, script) + installer.Install(d, json_path, apk=apk) return lambda: crash_handler.RetryOnSystemCrash( incremental_install_helper_internal, dev) if self._test_instance.apk_under_test: - if self._test_instance.apk_under_test_incremental_install_script: + if self._test_instance.apk_under_test_incremental_install_json: steps.append(incremental_install_helper( self._test_instance.apk_under_test, self._test_instance. - apk_under_test_incremental_install_script)) + apk_under_test_incremental_install_json)) else: permissions = self._test_instance.apk_under_test.GetPermissions() steps.append(install_helper(self._test_instance.apk_under_test, permissions)) - if self._test_instance.test_apk_incremental_install_script: + if self._test_instance.test_apk_incremental_install_json: steps.append(incremental_install_helper( self._test_instance.test_apk, self._test_instance. - test_apk_incremental_install_script)) + test_apk_incremental_install_json)) else: permissions = self._test_instance.test_apk.GetPermissions() steps.append(install_helper(self._test_instance.test_apk,
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py index 92a9035..94e9c82 100644 --- a/build/android/pylib/local/device/local_device_test_run.py +++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -3,7 +3,6 @@ # found in the LICENSE file. import fnmatch -import imp import logging import posixpath import signal @@ -26,28 +25,6 @@ ' Your test may not have run.') -def IncrementalInstall(device, apk_helper, installer_script): - """Performs an incremental install. - - Args: - device: Device to install on. - apk_helper: ApkHelper instance for the _incremental.apk. - installer_script: Path to the installer script for the incremental apk. - """ - try: - install_wrapper = imp.load_source('install_wrapper', installer_script) - except IOError: - raise Exception('Incremental install script not found: %s\n' % - installer_script) - params = install_wrapper.GetInstallParameters() - - from incremental_install import installer - installer.Install(device, apk_helper, split_globs=params['splits'], - native_libs=params['native_libs'], - dex_files=params['dex_files'], - permissions=None) # Auto-grant permissions from manifest. - - def SubstituteDeviceRoot(device_path, device_root): if not device_path: return device_root
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index ed0812b..01a0ec53 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -330,7 +330,7 @@ dest='suite_name', nargs='+', metavar='SUITE_NAME', required=True, help='Executable name of the test suite to run.') parser.add_argument( - '--test-apk-incremental-install-script', + '--test-apk-incremental-install-json', type=os.path.realpath, help='Path to install script for the test apk.') @@ -475,10 +475,10 @@ # These arguments are suppressed from the help text because they should # only ever be specified by an intermediate script. parser.add_argument( - '--apk-under-test-incremental-install-script', + '--apk-under-test-incremental-install-json', help=argparse.SUPPRESS) parser.add_argument( - '--test-apk-incremental-install-script', + '--test-apk-incremental-install-json', type=os.path.realpath, help=argparse.SUPPRESS)
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps index 4084940..1d03946 100644 --- a/build/android/test_runner.pydeps +++ b/build/android/test_runner.pydeps
@@ -113,9 +113,15 @@ ../../tools/swarming_client/libs/logdog/stream.py ../../tools/swarming_client/libs/logdog/streamname.py ../../tools/swarming_client/libs/logdog/varint.py +../gn_helpers.py ../util/lib/common/chrome_test_server_spawner.py ../util/lib/common/unittest_util.py devil_chromium.py +gyp/util/__init__.py +gyp/util/build_utils.py +gyp/util/md5_check.py +incremental_install/__init__.py +incremental_install/installer.py pylib/__init__.py pylib/android/__init__.py pylib/android/logdog_logcat_monitor.py @@ -179,6 +185,7 @@ pylib/utils/proguard.py pylib/utils/repo_utils.py pylib/utils/shared_preference_utils.py +pylib/utils/time_profile.py pylib/valgrind_tools.py test_runner.py tombstones.py
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 4228f64..8a8f6541 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -303,12 +303,12 @@ _rebased_apk_path = rebase_path(invoker.apk_path, root_build_dir) _rebased_incremental_apk_path = rebase_path(invoker.incremental_apk_path, root_build_dir) - _rebased_incremental_install_script_path = - rebase_path(invoker.incremental_install_script_path, root_build_dir) + _rebased_incremental_install_json_path = + rebase_path(invoker.incremental_install_json_path, root_build_dir) _incremental_allowed = defined(invoker.incremental_allowed) && invoker.incremental_allowed args += [ "--apk-path=$_rebased_apk_path" ] - args += [ "--incremental-install-script-path=$_rebased_incremental_install_script_path" ] + args += [ "--incremental-install-json-path=$_rebased_incremental_install_json_path" ] assert(_rebased_incremental_apk_path != "") # Mark as used. if (_incremental_allowed) { @@ -644,13 +644,13 @@ } if (_incremental_install) { test_runner_args += [ - "--test-apk-incremental-install-script", - "@FileArg($_rebased_apk_build_config:deps_info:incremental_install_script_path)", + "--test-apk-incremental-install-json", + "@FileArg($_rebased_apk_build_config:deps_info:incremental_install_json_path)", ] if (defined(invoker.apk_under_test)) { test_runner_args += [ - "--apk-under-test-incremental-install-script", - "@FileArg($_rebased_apk_under_test_build_config:deps_info:incremental_install_script_path)", + "--apk-under-test-incremental-install-json", + "@FileArg($_rebased_apk_under_test_build_config:deps_info:incremental_install_json_path)", ] } test_runner_args += [ "--fast-local-dev" ] @@ -1197,7 +1197,7 @@ (is_java_debug || dcheck_always_on) _desugar = defined(invoker.supports_android) && invoker.supports_android - + _deps = [] _previous_output_jar = _input_jar_path
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 648b14fe..a5fb140 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1647,16 +1647,8 @@ _final_apk_path_no_ext = _final_apk_path_no_ext_list[0] assert(_final_apk_path_no_ext != "") # Mark as used. - _install_script_name = "install_$_template_name" - if (defined(invoker.install_script_name)) { - _install_script_name = invoker.install_script_name - } - _incremental_install_script_path = - "${root_out_dir}/bin/${_install_script_name}" - if (!incremental_apk_by_default) { - _incremental_install_script_path = - "${_incremental_install_script_path}_incremental" - } + _incremental_install_json_path = + "$target_gen_dir/$target_name.incremental.json" _version_code = android_default_version_code if (defined(invoker.version_code)) { @@ -1814,7 +1806,7 @@ apk_path = _final_apk_path incremental_allowed = _incremental_allowed incremental_apk_path = "${_final_apk_path_no_ext}_incremental.apk" - incremental_install_script_path = _incremental_install_script_path + incremental_install_json_path = _incremental_install_json_path resources_zip = resources_zip_path build_config = _build_config android_manifest = _android_root_manifest @@ -2400,28 +2392,27 @@ } } - _create_incremental_script_rule_name = - "${_template_name}__incremental_script" - action(_create_incremental_script_rule_name) { - script = "//build/android/incremental_install/create_install_script.py" + _write_installer_json_rule_name = "${_template_name}__incremental_json" + action(_write_installer_json_rule_name) { + script = "//build/android/incremental_install/write_installer_json.py" depfile = "$target_gen_dir/$target_name.d" deps = [ _native_libs_file_arg_dep, ] outputs = [ - _incremental_install_script_path, + _incremental_install_json_path, ] _rebased_apk_path_no_ext = rebase_path(_final_apk_path_no_ext, root_build_dir) - _rebased_incremental_install_script_path = - rebase_path(_incremental_install_script_path, root_build_dir) + _rebased_incremental_install_json_path = + rebase_path(_incremental_install_json_path, root_build_dir) _rebased_depfile = rebase_path(depfile, root_build_dir) _dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files" args = [ "--apk-path=${_rebased_apk_path_no_ext}_incremental.apk", - "--script-output-path=$_rebased_incremental_install_script_path", + "--output-path=$_rebased_incremental_install_json_path", "--dex-file=$_rebased_lib_dex_path", "--dex-file-list=@FileArg($_dex_arg_key)", "--depfile=$_rebased_depfile", @@ -2465,6 +2456,8 @@ args = [ "--script-output-path", rebase_path(_generated_script, root_build_dir), + "--apk-path", + rebase_path(_final_apk_path, root_build_dir), ] if (defined(invoker.command_line_flags_file)) { args += [ @@ -2472,20 +2465,10 @@ invoker.command_line_flags_file, ] } - if (_incremental_allowed) { args += [ - "--incremental-apk-path", - rebase_path("${_final_apk_path_no_ext}_incremental.apk", - root_build_dir), - "--incremental-install-script", - rebase_path(_incremental_install_script_path, root_build_dir), - ] - } - if (!incremental_apk_by_default) { - args += [ - "--apk-path", - rebase_path(_final_apk_path, root_build_dir), + "--incremental-install-json-path", + rebase_path(_incremental_install_json_path, root_build_dir), ] } } @@ -2538,8 +2521,8 @@ # actual target, but instead loads them at runtime, we need to explicitly # depend on them here. public_deps = [ - ":${_create_incremental_script_rule_name}", ":${_template_name}__create_incremental", + ":${_write_installer_json_rule_name}", ":${java_target}", ] @@ -2592,7 +2575,6 @@ testonly = true _apk_target_name = "${target_name}__apk" _test_runner_target_name = "${target_name}__test_runner_script" - _install_script_name = "install_$target_name" _dist_ijar_path = "$root_build_dir/test.lib.java/" + invoker.apk_name + ".jar" _incremental_test_runner_target_name = @@ -2643,7 +2625,6 @@ deps = [] data_deps = [] forward_variables_from(invoker, "*") - install_script_name = _install_script_name deps += [ "//testing/android/broker:broker_java" ] data_deps += [ "//build/android/pylib/device/commands",
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 0f8e166..e6aa4dc 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -12264,6 +12264,9 @@ <message name="IDS_SCREEN_CAPTURE_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when screen capture is in progress."> Sharing screen </message> + <message name="IDS_VR_UNDER_DEVELOPMENT_NOTICE" desc="Text to be shown below the URL bar to announce that this is under development."> + This is an early release. Some features, like search and text entry, are not yet available. + </message> </if> <!-- VR specific strings -->
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 5d33e79..0429a755 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3204,7 +3204,10 @@ flag_descriptions::kDisableNewVirtualKeyboardBehaviorName, flag_descriptions::kDisableNewVirtualKeyboardBehaviorDescription, kOsCrOS, SINGLE_DISABLE_VALUE_TYPE(switches::kDisableNewVirtualKeyboardBehavior)}, -#endif // defined(OS_CHROMEOS) + {"enable-per-user-timezone", flag_descriptions::kEnablePerUserTimezoneName, + flag_descriptions::kEnablePerUserTimezoneDescription, kOsCrOS, + SINGLE_DISABLE_VALUE_TYPE(chromeos::switches::kDisablePerUserTimezone)}, +#endif // OS_CHROMEOS #if !defined(OS_ANDROID) {"enable-picture-in-picture",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 1c1fe0f..89ddfc0 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1859,8 +1859,6 @@ "settings/device_settings_provider_unittest.cc", "settings/device_settings_service_unittest.cc", "settings/install_attributes_unittest.cc", - "settings/scoped_cros_settings_test_helper.cc", - "settings/scoped_cros_settings_test_helper.h", "settings/session_manager_operation_unittest.cc", "settings/shutdown_policy_handler_unittest.cc", "settings/stub_cros_settings_provider_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc index 29bd74e2..c69c4ab2 100644 --- a/chrome/browser/chromeos/extensions/info_private_api.cc +++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -326,6 +326,13 @@ } if (property_name == kPropertyTimezone) { + if (chromeos::system::PerUserTimezoneEnabled()) { + return base::WrapUnique<base::Value>( + Profile::FromBrowserContext(context_) + ->GetPrefs() + ->GetUserPrefValue(prefs::kUserTimezone) + ->DeepCopy()); + } // TODO(crbug.com/697817): Convert CrosSettings::Get to take a unique_ptr. return base::WrapUnique<base::Value>( chromeos::CrosSettings::Get() @@ -363,8 +370,13 @@ if (param_name == kPropertyTimezone) { std::string param_value; EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, ¶m_value)); - chromeos::CrosSettings::Get()->Set(chromeos::kSystemTimezone, - base::Value(param_value)); + if (chromeos::system::PerUserTimezoneEnabled()) { + Profile::FromBrowserContext(context_)->GetPrefs()->SetString( + prefs::kUserTimezone, param_value); + } else { + chromeos::CrosSettings::Get()->Set(chromeos::kSystemTimezone, + base::Value(param_value)); + } } else { const char* pref_name = GetBoolPrefNameForApiProperty(param_name.c_str()); if (pref_name) {
diff --git a/chrome/browser/chromeos/extensions/info_private_apitest.cc b/chrome/browser/chromeos/extensions/info_private_apitest.cc index 12c568e..c3c88b1 100644 --- a/chrome/browser/chromeos/extensions/info_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/info_private_apitest.cc
@@ -44,9 +44,7 @@ IN_PROC_BROWSER_TEST_F(ChromeOSInfoPrivateTest, TestGetAndSet) { // Set the initial timezone different from what JS function // timezoneSetTest() will attempt to set. - base::Value initial_timezone("America/Los_Angeles"); - chromeos::CrosSettings::Get()->Set(chromeos::kSystemTimezone, - initial_timezone); + profile()->GetPrefs()->SetString(prefs::kUserTimezone, "America/Los_Angeles"); // Check that accessibility settings are set to default values. PrefService* prefs = profile()->GetPrefs();
diff --git a/chrome/browser/chromeos/login/screens/network_screen.cc b/chrome/browser/chromeos/login/screens/network_screen.cc index 1d78fd4..006b4c7 100644 --- a/chrome/browser/chromeos/login/screens/network_screen.cc +++ b/chrome/browser/chromeos/login/screens/network_screen.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/chromeos/login/screens/network_view.h" #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" #include "chrome/browser/chromeos/login/wizard_controller.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" #include "chrome/common/pref_names.h" @@ -133,12 +134,11 @@ } void NetworkScreen::SetTimezone(const std::string& timezone_id) { - std::string current_timezone_id; - CrosSettings::Get()->GetString(kSystemTimezone, ¤t_timezone_id); - if (current_timezone_id == timezone_id || timezone_id.empty()) + if (timezone_id.empty()) return; + timezone_ = timezone_id; - CrosSettings::Get()->SetString(kSystemTimezone, timezone_id); + chromeos::system::SetSystemAndSigninScreenTimezone(timezone_id); } std::string NetworkScreen::GetTimezone() const {
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc index 29c04248..d788e54e3 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -190,20 +190,29 @@ chromeos::LoginDisplayHost* display_host) { TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); + // Restore system timezone. + std::string timezone; + if (chromeos::system::PerUserTimezoneEnabled()) { + timezone = g_browser_process->local_state()->GetString( + prefs::kSigninScreenTimezone); + } + if (ShouldShowSigninScreen(first_screen)) { display_host->StartSignInScreen(chromeos::LoginScreenContext()); } else { display_host->StartWizard(first_screen); // Set initial timezone if specified by customization. - const std::string timezone_name = startup_manifest->initial_timezone(); - VLOG(1) << "Initial time zone: " << timezone_name; + const std::string customization_timezone = + startup_manifest->initial_timezone(); + VLOG(1) << "Initial time zone: " << customization_timezone; // Apply locale customizations only once to preserve whatever locale // user has changed to during OOBE. - if (!timezone_name.empty()) { - chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( - base::UTF8ToUTF16(timezone_name)); - } + if (!customization_timezone.empty()) + timezone = customization_timezone; + } + if (!timezone.empty()) { + chromeos::system::SetSystemAndSigninScreenTimezone(timezone); } }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc index 4e41a20..75f6af9 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -498,6 +498,7 @@ multi_profile_user_controller_->StartObserving(profile); } } + system::UpdateSystemTimezone(profile); UpdateUserTimeZoneRefresher(profile); break; }
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index beca138..b4af5ef 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -67,6 +67,7 @@ #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/device_disabling_manager.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/metrics/metrics_reporting_state.h" #include "chrome/browser/profiles/profile.h" @@ -1502,9 +1503,7 @@ if (!timezone->timeZoneId.empty()) { VLOG(1) << "Resolve TimeZone: setting timezone to '" << timezone->timeZoneId << "'"; - - system::TimezoneSettings::GetInstance()->SetTimezoneFromID( - base::UTF8ToUTF16(timezone->timeZoneId)); + chromeos::system::SetSystemAndSigninScreenTimezone(timezone->timeZoneId); } }
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc index d1a8418..3a583d6 100644 --- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc +++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -36,6 +36,7 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/chromeos/settings/install_attributes.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/policy/device_management_service_configuration.h" #include "chrome/common/pref_names.h" #include "chromeos/attestation/attestation_flow.h" @@ -354,8 +355,7 @@ if (chromeos::CrosSettings::Get()->GetString(chromeos::kSystemTimezonePolicy, &timezone) && !timezone.empty()) { - chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( - base::UTF8ToUTF16(timezone)); + chromeos::system::SetSystemAndSigninScreenTimezone(timezone); } }
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index c88005e..52e9b6c 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -25,8 +25,11 @@ #include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/chromeos/system/timezone_resolver_manager.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/prefs/pref_service_syncable_util.h" #include "chrome/browser/ui/ash/ash_util.h" @@ -34,6 +37,7 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/chromeos_switches.h" +#include "chromeos/settings/cros_settings_names.h" #include "chromeos/system/devicemode.h" #include "chromeos/system/statistics_provider.h" #include "chromeos/timezone/timezone_resolver.h" @@ -116,6 +120,7 @@ registry->RegisterBooleanPref(prefs::kAccessibilityMonoAudioEnabled, false); registry->RegisterStringPref(prefs::kLogoutStartedLast, std::string()); + registry->RegisterStringPref(prefs::kSigninScreenTimezone, std::string()); registry->RegisterBooleanPref(prefs::kResolveDeviceTimezoneByGeolocation, true); registry->RegisterIntegerPref( @@ -353,6 +358,16 @@ input_method::InputMethodSyncer::RegisterProfilePrefs(registry); + std::string current_timezone_id; + if (chromeos::CrosSettings::IsInitialized()) { + // In unit tests CrosSettings is not always initialized. + chromeos::CrosSettings::Get()->GetString(kSystemTimezone, + ¤t_timezone_id); + } + // |current_timezone_id| will be empty if CrosSettings doesn't know the + // timezone yet. + registry->RegisterStringPref(prefs::kUserTimezone, current_timezone_id); + registry->RegisterBooleanPref( prefs::kResolveTimezoneByGeolocation, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); @@ -432,6 +447,7 @@ callback); pref_change_registrar_.Init(prefs); + pref_change_registrar_.Add(prefs::kUserTimezone, callback); pref_change_registrar_.Add(prefs::kResolveTimezoneByGeolocation, callback); pref_change_registrar_.Add(prefs::kUse24HourClock, callback); for (auto* remap_pref : kLanguageRemapPrefs) @@ -727,6 +743,11 @@ static_cast<WakeOnWifiManager::WakeOnWifiFeature>(features)); } + if (pref_name == prefs::kUserTimezone && + reason != REASON_ACTIVE_USER_CHANGED) { + system::UpdateSystemTimezone(ProfileHelper::Get()->GetProfileByUser(user_)); + } + if (pref_name == prefs::kResolveTimezoneByGeolocation && reason != REASON_ACTIVE_USER_CHANGED) { const bool value = prefs_->GetBoolean(prefs::kResolveTimezoneByGeolocation);
diff --git a/chrome/browser/chromeos/printing/printer_info.h b/chrome/browser/chromeos/printing/printer_info.h index 5b7403f..df7ca69 100644 --- a/chrome/browser/chromeos/printing/printer_info.h +++ b/chrome/browser/chromeos/printing/printer_info.h
@@ -28,6 +28,7 @@ void QueryIppPrinter(const std::string& host, const int port, const std::string& path, + bool encrypted, const PrinterInfoCallback& callback); } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printer_info_cups.cc b/chrome/browser/chromeos/printing/printer_info_cups.cc index 27e6208..d5fd2c97 100644 --- a/chrome/browser/chromeos/printing/printer_info_cups.cc +++ b/chrome/browser/chromeos/printing/printer_info_cups.cc
@@ -81,9 +81,10 @@ std::unique_ptr<::printing::PrinterInfo> QueryPrinterImpl( const std::string& host, const int port, - const std::string& path) { + const std::string& path, + bool encrypted) { auto info = base::MakeUnique<::printing::PrinterInfo>(); - if (!::printing::GetPrinterInfo(host, port, path, info.get())) { + if (!::printing::GetPrinterInfo(host, port, path, encrypted, info.get())) { LOG(ERROR) << "Could not retrieve printer info"; return nullptr; } @@ -125,6 +126,7 @@ void QueryIppPrinter(const std::string& host, const int port, const std::string& path, + bool encrypted, const PrinterInfoCallback& callback) { DCHECK(!host.empty()); @@ -134,7 +136,7 @@ base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, base::TaskTraits(base::TaskPriority::USER_VISIBLE, base::MayBlock()), - base::Bind(&QueryPrinterImpl, host, port, path), + base::Bind(&QueryPrinterImpl, host, port, path, encrypted), base::Bind(&OnPrinterQueried, callback)); }
diff --git a/chrome/browser/chromeos/printing/printer_info_stub.cc b/chrome/browser/chromeos/printing/printer_info_stub.cc index 6832229..85bd76b 100644 --- a/chrome/browser/chromeos/printing/printer_info_stub.cc +++ b/chrome/browser/chromeos/printing/printer_info_stub.cc
@@ -12,6 +12,7 @@ void QueryIppPrinter(const std::string& host, const int port, const std::string& path, + bool encrypted, const PrinterInfoCallback& callback) { DCHECK(!host.empty());
diff --git a/chrome/browser/chromeos/settings/system_settings_provider.cc b/chrome/browser/chromeos/settings/system_settings_provider.cc index e636b91..02b9d11 100644 --- a/chrome/browser/chromeos/settings/system_settings_provider.cc +++ b/chrome/browser/chromeos/settings/system_settings_provider.cc
@@ -7,6 +7,7 @@ #include "base/strings/string16.h" #include "base/time/time.h" #include "base/values.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chromeos/login/login_state.h" #include "chromeos/settings/cros_settings_names.h" @@ -20,6 +21,8 @@ timezone_settings->AddObserver(this); timezone_value_.reset( new base::Value(timezone_settings->GetCurrentTimezoneID())); + per_user_timezone_enabled_value_.reset( + new base::Value(system::PerUserTimezoneEnabled())); } SystemSettingsProvider::~SystemSettingsProvider() { @@ -41,11 +44,16 @@ // This will call TimezoneChanged. system::TimezoneSettings::GetInstance()->SetTimezoneFromID(timezone_id); } + // kPerUserTimezoneEnabled is read-only. } const base::Value* SystemSettingsProvider::Get(const std::string& path) const { if (path == kSystemTimezone) return timezone_value_.get(); + + if (path == kPerUserTimezoneEnabled) + return per_user_timezone_enabled_value_.get(); + return NULL; } @@ -56,7 +64,7 @@ } bool SystemSettingsProvider::HandlesSetting(const std::string& path) const { - return path == kSystemTimezone; + return path == kSystemTimezone || path == kPerUserTimezoneEnabled; } void SystemSettingsProvider::TimezoneChanged(const icu::TimeZone& timezone) {
diff --git a/chrome/browser/chromeos/settings/system_settings_provider.h b/chrome/browser/chromeos/settings/system_settings_provider.h index e61761f..c72b60f 100644 --- a/chrome/browser/chromeos/settings/system_settings_provider.h +++ b/chrome/browser/chromeos/settings/system_settings_provider.h
@@ -39,6 +39,7 @@ void DoSet(const std::string& path, const base::Value& in_value) override; std::unique_ptr<base::Value> timezone_value_; + std::unique_ptr<base::Value> per_user_timezone_enabled_value_; DISALLOW_COPY_AND_ASSIGN(SystemSettingsProvider); };
diff --git a/chrome/browser/chromeos/system/timezone_util.cc b/chrome/browser/chromeos/system/timezone_util.cc index d01f60e..c7facbb 100644 --- a/chrome/browser/chromeos/system/timezone_util.cc +++ b/chrome/browser/chromeos/system/timezone_util.cc
@@ -10,6 +10,7 @@ #include <string> #include <utility> +#include "base/command_line.h" #include "base/i18n/rtl.h" #include "base/i18n/unicodestring.h" #include "base/lazy_instance.h" @@ -21,13 +22,18 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/timezone_resolver_manager.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/chromeos_switches.h" #include "chromeos/settings/timezone_settings.h" #include "chromeos/timezone/timezone_request.h" #include "components/prefs/pref_service.h" +#include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "third_party/icu/source/common/unicode/ures.h" #include "third_party/icu/source/common/unicode/utypes.h" @@ -184,6 +190,42 @@ return false; } +bool IsTimezonePrefsManaged(const std::string& pref_name) { + DCHECK(pref_name == prefs::kUserTimezone || + pref_name == prefs::kResolveTimezoneByGeolocation); + + std::string policy_timezone; + if (chromeos::CrosSettings::Get()->GetString(chromeos::kSystemTimezonePolicy, + &policy_timezone) && + !policy_timezone.empty()) { + return true; + } + + const PrefService* local_state = g_browser_process->local_state(); + if (!local_state->IsManagedPreference( + prefs::kSystemTimezoneAutomaticDetectionPolicy)) { + return false; + } + + int resolve_policy_value = + local_state->GetInteger(prefs::kSystemTimezoneAutomaticDetectionPolicy); + + switch (resolve_policy_value) { + case enterprise_management::SystemTimezoneProto::USERS_DECIDE: + return false; + case enterprise_management::SystemTimezoneProto::DISABLED: + // This only disables resolving. + return pref_name == prefs::kResolveTimezoneByGeolocation; + case enterprise_management::SystemTimezoneProto::IP_ONLY: + case enterprise_management::SystemTimezoneProto::SEND_WIFI_ACCESS_POINTS: + case enterprise_management::SystemTimezoneProto::SEND_ALL_LOCATION_INFO: + return true; + } + // Default for unknown policy value. + NOTREACHED() << "Unrecognized policy value: " << resolve_policy_value; + return true; +} + void ApplyTimeZone(const TimeZoneResponseData* timezone) { if (!g_browser_process->platform_part() ->GetTimezoneResolverManager() @@ -195,10 +237,97 @@ VLOG(1) << "Refresh TimeZone: setting timezone to '" << timezone->timeZoneId << "'"; - chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( - base::UTF8ToUTF16(timezone->timeZoneId)); + if (PerUserTimezoneEnabled()) { + const user_manager::UserManager* user_manager = + user_manager::UserManager::Get(); + const user_manager::User* primary_user = user_manager->GetPrimaryUser(); + + if (primary_user) { + Profile* profile = ProfileHelper::Get()->GetProfileByUser(primary_user); + profile->GetPrefs()->SetString(prefs::kUserTimezone, + timezone->timeZoneId); + // chromeos::Preferences::ApplyPreferences() will automatically change + // system timezone because user is primary. + } else { + SetSystemAndSigninScreenTimezone(timezone->timeZoneId); + } + } else { + chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( + base::UTF8ToUTF16(timezone->timeZoneId)); + } } } +void UpdateSystemTimezone(Profile* profile) { + if (IsTimezonePrefsManaged(prefs::kUserTimezone)) { + VLOG(1) << "Ignoring user timezone change, because timezone is enterprise " + "managed."; + return; + } + + const user_manager::UserManager* user_manager = + user_manager::UserManager::Get(); + const user_manager::User* user = + ProfileHelper::Get()->GetUserByProfile(profile); + + const AccountId owner(user_manager->GetOwnerAccountId()); + const bool user_is_owner = + owner.is_valid() && (owner == user->GetAccountId()); + + const std::string value = + profile->GetPrefs()->GetString(prefs::kUserTimezone); + if (user_is_owner) { + g_browser_process->local_state()->SetString(prefs::kSigninScreenTimezone, + value); + } + + if (user_manager->GetPrimaryUser() == user && PerUserTimezoneEnabled()) + CrosSettings::Get()->SetString(kSystemTimezone, value); +} + +void SetSystemAndSigninScreenTimezone(const std::string& timezone) { + if (timezone.empty()) + return; + + g_browser_process->local_state()->SetString(prefs::kSigninScreenTimezone, + timezone); + + std::string current_timezone_id; + CrosSettings::Get()->GetString(kSystemTimezone, ¤t_timezone_id); + if (current_timezone_id != timezone) { + system::TimezoneSettings::GetInstance()->SetTimezoneFromID( + base::UTF8ToUTF16(timezone)); + } +} + +bool PerUserTimezoneEnabled() { + return !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisablePerUserTimezone); +} + +void SetTimezoneFromUI(Profile* profile, const std::string& timezone_id) { + if (!PerUserTimezoneEnabled()) { + CrosSettings::Get()->SetString(kSystemTimezone, timezone_id); + return; + } + + if (ProfileHelper::IsSigninProfile(profile)) { + SetSystemAndSigninScreenTimezone(timezone_id); + return; + } + + if (ProfileHelper::IsEphemeralUserProfile(profile)) { + CrosSettings::Get()->SetString(kSystemTimezone, timezone_id); + return; + } + + Profile* primary_profile = ProfileManager::GetPrimaryUserProfile(); + if (primary_profile && profile->IsSameProfile(primary_profile)) { + profile->GetPrefs()->SetString(prefs::kUserTimezone, timezone_id); + } + // Time zone UI should be blocked for non-primary users. + NOTREACHED(); +} + } // namespace system } // namespace chromeos
diff --git a/chrome/browser/chromeos/system/timezone_util.h b/chrome/browser/chromeos/system/timezone_util.h index 92d8ade..ee6e612 100644 --- a/chrome/browser/chromeos/system/timezone_util.h +++ b/chrome/browser/chromeos/system/timezone_util.h
@@ -9,6 +9,8 @@ #include "base/strings/string16.h" +class Profile; + namespace base { class ListValue; } @@ -31,6 +33,29 @@ // Apply TimeZone update from TimeZoneProvider. void ApplyTimeZone(const TimeZoneResponseData* timezone); +// Returns true if given timezone preference is enterprise-managed. +// Works for: +// - prefs::kUserTimezone +// - prefs::kResolveTimezoneByGeolocation +bool IsTimezonePrefsManaged(const std::string& pref_name); + +// Updates system timezone from user profile data if needed. +// This is called from chromeos::Preferences after updating profile +// preferences to apply new value to system time zone. +void UpdateSystemTimezone(Profile* profile); + +// Updates Local State preference prefs::kSigninScreenTimezone AND +// also immediately sets system timezone (chromeos::system::TimezoneSettings). +// This is called when there is no user session (i.e. OOBE and signin screen), +// or when device policies are updated. +void SetSystemAndSigninScreenTimezone(const std::string& timezone); + +// Returns true if per-user timezone preferences are enabled. +bool PerUserTimezoneEnabled(); + +// This is called from UI code to apply user-selected time zone. +void SetTimezoneFromUI(Profile* profile, const std::string& timezone_id); + } // namespace system } // namespace chromeos
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 882be39..1749f60 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -40,6 +40,7 @@ #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chromeos/settings/cros_settings_names.h" #include "ui/chromeos/events/pref_names.h" #endif @@ -50,13 +51,23 @@ bool IsPrivilegedCrosSetting(const std::string& pref_name) { if (!chromeos::CrosSettings::IsCrosSettings(pref_name)) return false; - // kSystemTimezone should be changeable by all users. - if (pref_name == chromeos::kSystemTimezone) - return false; - // All other Cros settings are considered privileged and are either policy + if (!chromeos::system::PerUserTimezoneEnabled()) { + // kSystemTimezone should be changeable by all users. + if (pref_name == chromeos::kSystemTimezone) + return false; + } + // Cros settings are considered privileged and are either policy // controlled or owner controlled. return true; } + +bool IsCrosSettingReadOnly(const std::string& pref_name) { + if (chromeos::system::PerUserTimezoneEnabled()) { + // System timezone is never directly changable by user. + return pref_name == chromeos::kSystemTimezone; + } + return false; +} #endif } // namespace @@ -302,9 +313,13 @@ // Timezone settings. (*s_whitelist)[chromeos::kSystemTimezone] = - settings_private::PrefType::PREF_TYPE_BOOLEAN; + settings_private::PrefType::PREF_TYPE_STRING; + (*s_whitelist)[prefs::kUserTimezone] = + settings_private::PrefType::PREF_TYPE_STRING; (*s_whitelist)[::prefs::kResolveTimezoneByGeolocation] = settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[chromeos::kPerUserTimezoneEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; // Ash settings. (*s_whitelist)[::prefs::kEnableStylusTools] = @@ -474,6 +489,21 @@ } #if defined(OS_CHROMEOS) + // We first check for enterprise-managed, then for primary-user managed. + // Otherwise in multiprofile mode enterprise preference for the secondary + // user will appear primary-user-controlled, which looks strange, because + // primary user preference will be disabled with "enterprise controlled" + // status. + if (IsPrefEnterpriseManaged(name)) { + // Enterprise managed prefs are treated the same as device policy restricted + // prefs in the UI. + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_DEVICE_POLICY; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; + return pref_object; + } + if (IsPrefPrimaryUserControlled(name)) { pref_object->controlled_by = settings_private::ControlledBy::CONTROLLED_BY_PRIMARY_USER; @@ -486,16 +516,6 @@ .GetUserEmail())); return pref_object; } - - if (IsPrefEnterpriseManaged(name)) { - // Enterprise managed prefs are treated the same as device policy restricted - // prefs in the UI. - pref_object->controlled_by = - settings_private::ControlledBy::CONTROLLED_BY_DEVICE_POLICY; - pref_object->enforcement = - settings_private::Enforcement::ENFORCEMENT_ENFORCED; - return pref_object; - } #endif if (pref && pref->IsManaged()) { @@ -681,16 +701,26 @@ #if defined(OS_CHROMEOS) bool PrefsUtil::IsPrefEnterpriseManaged(const std::string& pref_name) { - if (IsPrivilegedCrosSetting(pref_name)) { - policy::BrowserPolicyConnectorChromeOS* connector = - g_browser_process->platform_part()->browser_policy_connector_chromeos(); - if (connector->IsEnterpriseManaged()) - return true; + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + if (!connector->IsEnterpriseManaged()) + return false; + if (IsPrivilegedCrosSetting(pref_name)) + return true; + if (chromeos::system::PerUserTimezoneEnabled() && + (pref_name == prefs::kUserTimezone || + pref_name == prefs::kResolveTimezoneByGeolocation)) { + return chromeos::system::IsTimezonePrefsManaged(pref_name); } return false; } bool PrefsUtil::IsPrefOwnerControlled(const std::string& pref_name) { + // chromeos::kSystemTimezone is global display-only preference and + // it should appear as disabled, but not owned. + if (pref_name == chromeos::kSystemTimezone) + return false; + if (IsPrivilegedCrosSetting(pref_name)) { if (!chromeos::ProfileHelper::IsOwnerProfile(profile_)) return true; @@ -699,13 +729,19 @@ } bool PrefsUtil::IsPrefPrimaryUserControlled(const std::string& pref_name) { - if (pref_name == prefs::kWakeOnWifiDarkConnect) { + // chromeos::kSystemTimezone is read-only, but for the non-primary users + // it should have "primary user controlled" attribute. + if (pref_name == prefs::kWakeOnWifiDarkConnect || + pref_name == prefs::kResolveTimezoneByGeolocation || + pref_name == prefs::kUserTimezone || + pref_name == chromeos::kSystemTimezone) { user_manager::UserManager* user_manager = user_manager::UserManager::Get(); const user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); - if (user && - user->GetAccountId() != user_manager->GetPrimaryUser()->GetAccountId()) + if (user && user->GetAccountId() != + user_manager->GetPrimaryUser()->GetAccountId()) { return true; + } } return false; } @@ -720,6 +756,11 @@ } bool PrefsUtil::IsPrefUserModifiable(const std::string& pref_name) { +#if defined(OS_CHROMEOS) + if (IsCrosSettingReadOnly(pref_name)) + return false; +#endif + const PrefService::Preference* profile_pref = profile_->GetPrefs()->FindPreference(pref_name); if (profile_pref)
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 1663dcd..8cbe8de 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2081,6 +2081,11 @@ "Enables Instant Tethering. Instant Tethering allows your nearby Google " "phone to share its Internet connection with this device."; +const char kEnablePerUserTimezoneName[] = "Per-user time zone preferences."; +const char kEnablePerUserTimezoneDescription[] = + "Chrome OS system timezone preference is stored and handled for each user " + "individually."; + #endif // defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 11e3ff4..90e0e25 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1317,6 +1317,9 @@ extern const char kDisableNewVirtualKeyboardBehaviorName[]; extern const char kDisableNewVirtualKeyboardBehaviorDescription[]; +extern const char kEnablePerUserTimezoneName[]; +extern const char kEnablePerUserTimezoneDescription[]; + extern const char kDisableSystemTimezoneAutomaticDetectionName[]; extern const char kDisableSystemTimezoneAutomaticDetectionDescription[];
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 3d2ce964..e299d65 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html
@@ -329,7 +329,7 @@ <select class="control" id="timezone-value-select" i18n-options="timezoneList" data-type="string" - pref="cros.system.timezone" + pref="settings.timezone" aria-labelledby="timezone-value-label" metric="Options_TimezoneSelect"></select> </div>
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html index b40d202..edab66b 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.html +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -35,25 +35,61 @@ <div id="timezoneGeolocateToggleLabel" class="start"> $i18n{timeZoneGeolocation} </div> - <template is="dom-if" if="[[hasTimeZoneAutoDetectPolicy_]]" restamp> - <cr-policy-indicator indicator-type="devicePolicy" - icon-aria-label="$i18n{timeZoneGeolocation}"> - </cr-policy-indicator> + <template is="dom-if" restamp + if="[[!prefs.cros.flags.per_user_timezone_enabled.value]]"> + <template is="dom-if" if="[[hasTimeZoneAutoDetectPolicy_]]" restamp> + <cr-policy-indicator indicator-type="devicePolicy" + icon-aria-label="$i18n{timeZoneGeolocation}"> + </cr-policy-indicator> + </template> + <paper-toggle-button + id="timeZoneAutoDetect" + aria-labelledby="timezoneGeolocateToggleLabel" + checked="[[timeZoneAutoDetect_]]" + disabled="[[hasTimeZoneAutoDetectPolicy_]]" + on-change="onTimeZoneAutoDetectChange_"> + </paper-toggle-button> </template> - <paper-toggle-button - id="timeZoneAutoDetect" - aria-labelledby="timezoneGeolocateToggleLabel" - checked="[[timeZoneAutoDetect_]]" - disabled="[[hasTimeZoneAutoDetectPolicy_]]" - on-change="onTimeZoneAutoDetectChange_"> - </paper-toggle-button> + <template is="dom-if" restamp + if="[[prefs.cros.flags.per_user_timezone_enabled.value]]"> + <settings-toggle-button + pref="{{prefs.settings.resolve_timezone_by_geolocation}}" + id="timeZoneAutoDetect" + aria-labelledby="timezoneGeolocateToggleLabel"> + </settings-toggle-button> + </template> </div> <div class="settings-box continuation embedded"> - <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}" - label="$i18n{timeZone}" - menu-options="[[timeZoneList_]]" - disabled="[[timeZoneAutoDetect_]]"> - </settings-dropdown-menu> + <template is="dom-if" restamp + if="[[!prefs.cros.flags.per_user_timezone_enabled.value]]"> + <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}" + label="$i18n{timeZone}" + menu-options="[[timeZoneList_]]" + disabled="[[timeZoneAutoDetect_]]"> + </settings-dropdown-menu> + </template> + <template is="dom-if" restamp + if="[[prefs.cros.flags.per_user_timezone_enabled.value]]"> + <template is="dom-if" if="[[!isUserTimeZoneSelectorHidden_( + prefs.settings.timezone, + prefs.settings.resolve_timezone_by_geolocation.value)]]" restamp> + <settings-dropdown-menu id="userTimeZoneSelector" + pref="{{prefs.settings.timezone}}" + label="$i18n{timeZone}" + menu-options="[[timeZoneList_]]"> + </settings-dropdown-menu> + </template> + <template is="dom-if" if="[[isUserTimeZoneSelectorHidden_( + prefs.settings.timezone, + prefs.settings.resolve_timezone_by_geolocation.value)]]" restamp> + <settings-dropdown-menu id="systemTimezoneSelector" + pref="{{prefs.cros.system.timezone}}" + label="$i18n{timeZone}" + menu-options="[[timeZoneList_]]" + disabled> + </settings-dropdown-menu> + </template> + </template> </div> <div class="settings-box"> <settings-toggle-button class="start"
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js index 3b004f2..ef37894 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.js +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -90,7 +90,9 @@ }, observers: [ - 'maybeGetTimeZoneList_(' + + 'maybeGetTimeZoneListPerUser_(' + + 'prefs.settings.timezone.value, timeZoneAutoDetect_)', + 'maybeGetTimeZoneListPerSystem_(' + 'prefs.cros.system.timezone.value, timeZoneAutoDetect_)', ], @@ -174,24 +176,54 @@ /** * Fetches the list of time zones if necessary. + * @param {boolean=} perUserTimeZoneMode Expected value of per-user time zone. * @private */ - maybeGetTimeZoneList_: function() { + maybeGetTimeZoneList_: function(perUserTimeZoneMode) { + if (typeof(perUserTimeZoneMode) !== 'undefined') { + /* This method is called as observer. Skip if if current mode does not + * match expected. + */ + if (perUserTimeZoneMode != + this.getPref('cros.flags.per_user_timezone_enabled').value) { + return; + } + } // Only fetch the list once. if (this.timeZoneList_.length > 1 || !CrSettingsPrefs.isInitialized) return; // If auto-detect is enabled, we only need the current time zone. - if (this.timeZoneAutoDetect_ && - this.getPref('cros.system.timezone').value == - this.timeZoneList_[0].value) { - return; + if (this.timeZoneAutoDetect_) { + var isPerUserTimezone = + this.getPref('cros.flags.per_user_timezone_enabled').value; + if (this.timeZoneList_[0].value == + (isPerUserTimezone ? this.getPref('settings.timezone').value : + this.getPref('cros.system.timezone').value)) { + return; + } } cr.sendWithPromise('getTimeZones').then(this.setTimeZoneList_.bind(this)); }, /** + * Prefs observer for Per-user time zone enabled mode. + * @private + */ + maybeGetTimeZoneListPerUser_: function() { + this.maybeGetTimeZoneList_(true); + }, + + /** + * Prefs observer for Per-user time zone disabled mode. + * @private + */ + maybeGetTimeZoneListPerSystem_: function() { + this.maybeGetTimeZoneList_(false); + }, + + /** * Converts the C++ response into an array of menu options. * @param {!Array<!Array<string>>} timeZones C++ time zones response. * @private @@ -204,4 +236,17 @@ }; }); }, + + /** + * Computes visibility of user timezone preference. + * @param {?chrome.settingsPrivate.PrefObject} prefUserTimezone + * pref.settings.timezone + * @param {boolean} prefResolveValue + * prefs.settings.resolve_timezone_by_geolocation.value + * @private + */ + isUserTimeZoneSelectorHidden_: function(prefUserTimezone, prefResolveValue) { + return (prefUserTimezone && prefUserTimezone.controlledBy != null) || + prefResolveValue; + }, });
diff --git a/chrome/browser/ui/webui/chromeos/set_time_ui.cc b/chrome/browser/ui/webui/chromeos/set_time_ui.cc index 98871678..bc44b7e 100644 --- a/chrome/browser/ui/webui/chromeos/set_time_ui.cc +++ b/chrome/browser/ui/webui/chromeos/set_time_ui.cc
@@ -22,6 +22,7 @@ #include "chromeos/dbus/system_clock_client.h" #include "chromeos/login/login_state.h" #include "chromeos/settings/timezone_settings.h" +#include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_message_handler.h" @@ -63,6 +64,10 @@ web_ui()->CallJavascriptFunctionUnsafe("settime.TimeSetter.updateTime"); } + // UI actually shows real device timezone, but only allows changing the user + // timezone. If user timezone settings are different from system, this means + // that user settings are overriden and must be disabled. (And we will still + // show the actual device timezone.) // system::TimezoneSettings::Observer: void TimezoneChanged(const icu::TimeZone& timezone) override { base::Value timezone_id(system::TimezoneSettings::GetTimezoneID(timezone)); @@ -94,7 +99,10 @@ return; } - CrosSettings::Get()->SetString(kSystemTimezone, timezone_id); + Profile* profile = Profile::FromBrowserContext( + web_ui()->GetWebContents()->GetBrowserContext()); + DCHECK(profile); + system::SetTimezoneFromUI(profile, timezone_id); } DISALLOW_COPY_AND_ASSIGN(SetTimeMessageHandler);
diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc index 71db18f..201f458 100644 --- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/proxy_cros_settings_parser.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/session_controller_client.h" #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h" @@ -47,20 +48,34 @@ namespace { -// List of settings that should be changeable by all users. -const char* kNonPrivilegedSettings[] = { +// List of settings that are not changeable by users. +const char* kReadOnlySettings[] = { kSystemTimezone }; // List of settings that should only be changeable by the primary user. const char* kPrimaryUserSettings[] = { prefs::kWakeOnWifiDarkConnect, + prefs::kUserTimezone, + prefs::kResolveTimezoneByGeolocation }; // Returns true if |pref| can be controlled (e.g. by policy or owner). bool IsSettingPrivileged(const std::string& pref) { - const char** end = kNonPrivilegedSettings + arraysize(kNonPrivilegedSettings); - return std::find(kNonPrivilegedSettings, end, pref) == end; + if (!chromeos::system::PerUserTimezoneEnabled()) { + return pref != kSystemTimezone; + } + // All the other Cros Settings are controlled. + return true; +} + +// Returns true if |pref| is modifiable from UI. +bool IsSettingWritable(const std::string& pref) { + if (!system::PerUserTimezoneEnabled()) + return true; + + const char** end = kReadOnlySettings + arraysize(kReadOnlySettings); + return std::find(kReadOnlySettings, end, pref) == end; } // Returns true if |pref| is shared (controlled by the primary user). @@ -200,8 +215,14 @@ return value; dict->SetString("controlledBy", "shared"); dict->SetBoolean("disabled", true); - dict->SetBoolean("value", primary_profile->GetPrefs()->GetBoolean( - pref_name)); + if (system::PerUserTimezoneEnabled()) { + const PrefService::Preference* pref = + primary_profile->GetPrefs()->FindPreference(pref_name); + dict->Set("value", base::MakeUnique<base::Value>(*pref->GetValue())); + } else { + dict->SetBoolean("value", + primary_profile->GetPrefs()->GetBoolean(pref_name)); + } return value; } @@ -218,7 +239,7 @@ dict->Set("value", base::MakeUnique<base::Value>(*pref_value)); std::string controlled_by; - if (IsSettingPrivileged(pref_name)) { + if (system::PerUserTimezoneEnabled() || IsSettingPrivileged(pref_name)) { policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos(); if (connector->IsEnterpriseManaged()) @@ -226,9 +247,12 @@ else if (!ProfileHelper::IsOwnerProfile(profile)) controlled_by = "owner"; } - dict->SetBoolean("disabled", !controlled_by.empty()); if (!controlled_by.empty()) dict->SetString("controlledBy", controlled_by); + + // Read-only setting is always disabled. + dict->SetBoolean("disabled", + !controlled_by.empty() || !IsSettingWritable(pref_name)); return std::move(dict); } @@ -262,6 +286,10 @@ } if (!CrosSettings::IsCrosSettings(pref_name)) return ::options::CoreOptionsHandler::SetPref(pref_name, value, metric); + if (!IsSettingWritable(pref_name)) { + NOTREACHED() << pref_name; + return; + } OwnerSettingsServiceChromeOS* service = OwnerSettingsServiceChromeOS::FromWebUI(web_ui()); if (service && service->HandlesSetting(pref_name))
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 2d8a809f..96389b0 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -54,6 +54,8 @@ const char kIppsScheme[] = "ipps"; const int kIppPort = 631; +// IPPS commonly uses the HTTPS port despite the spec saying it should use the +// IPP port. const int kIppsPort = 443; // These values are written to logs. New enum values can be added, but existing @@ -311,21 +313,23 @@ url::ParseStandardURL(uri_ptr, printer_uri.length(), &parsed); base::StringPiece host(&printer_uri[parsed.host.begin], parsed.host.len); + bool encrypted = printer_protocol != kIppScheme; int port = ParsePort(uri_ptr, parsed.port); + // Port not specified. if (port == url::SpecialPort::PORT_UNSPECIFIED || port == url::SpecialPort::PORT_INVALID) { - // imply port from protocol if (printer_protocol == kIppScheme) { port = kIppPort; } else if (printer_protocol == kIppsScheme) { - // ipps is ipp over https so it uses the https port. port = kIppsPort; } else { + // Port was not defined explicitly and scheme is not recognized. Cannot + // infer a port number. NOTREACHED() << "Unrecognized protocol. Port was not set."; } } - QueryIppPrinter(host.as_string(), port, printer_queue, + QueryIppPrinter(host.as_string(), port, printer_queue, encrypted, base::Bind(&CupsPrintersHandler::OnPrinterInfo, weak_factory_.GetWeakPtr(), callback_id)); }
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn index 985ad1c..3e17b74 100644 --- a/chrome/browser/vr/BUILD.gn +++ b/chrome/browser/vr/BUILD.gn
@@ -65,6 +65,8 @@ "elements/system_indicator.h", "elements/system_indicator_texture.cc", "elements/system_indicator_texture.h", + "elements/text.cc", + "elements/text.h", "elements/textured_element.cc", "elements/textured_element.h", "elements/transience_manager.cc",
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc new file mode 100644 index 0000000..c8909ec --- /dev/null +++ b/chrome/browser/vr/elements/text.cc
@@ -0,0 +1,86 @@ +// 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/vr/elements/text.h" + +#include "base/memory/ptr_util.h" +#include "cc/paint/skia_paint_canvas.h" +#include "chrome/browser/vr/elements/ui_texture.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/render_text.h" + +namespace vr { + +class TextTexture : public UiTexture { + public: + TextTexture(int resource_id, float font_height, float text_width) + : resource_id_(resource_id), + font_height_(font_height), + text_width_(text_width) {} + ~TextTexture() override {} + + private: + gfx::Size GetPreferredTextureSize(int width) const override { + return gfx::Size(width, width); + } + + gfx::SizeF GetDrawnSize() const override { return size_; } + + void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override; + + gfx::SizeF size_; + int resource_id_; + // These widths are in meters. + float font_height_; + float text_width_; + // TODO(vollick): this should be parameterized. + SkColor text_color_ = 0xFF363636; + + DISALLOW_COPY_AND_ASSIGN(TextTexture); +}; + +Text::Text(int maximum_width_pixels, + float font_height_meters, + float text_width_meters, + int resource_id) + : TexturedElement(maximum_width_pixels), + texture_(base::MakeUnique<TextTexture>(resource_id, + font_height_meters, + text_width_meters)) {} +Text::~Text() {} + +UiTexture* Text::GetTexture() const { + return texture_.get(); +} + +void TextTexture::Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) { + cc::SkiaPaintCanvas paint_canvas(sk_canvas); + gfx::Canvas gfx_canvas(&paint_canvas, 1.0f); + gfx::Canvas* canvas = &gfx_canvas; + + gfx::FontList fonts; + auto text = l10n_util::GetStringUTF16(resource_id_); + float pixels_per_meter = texture_size.width() / text_width_; + int pixel_font_height = static_cast<int>(font_height_ * pixels_per_meter); + GetFontList(pixel_font_height, text, &fonts); + gfx::Rect text_bounds(texture_size.width(), 0); + + std::vector<std::unique_ptr<gfx::RenderText>> lines = + // TODO(vollick): if this subsumes all text, then we should probably move + // this function into this class. + PrepareDrawStringRect(text, fonts, text_color_, &text_bounds, + kTextAlignmentCenter, kWrappingBehaviorWrap); + // Draw the text. + for (auto& render_text : lines) + render_text->Draw(canvas); + + // Note, there is no padding here whatsoever. + size_ = gfx::SizeF(text_bounds.size()); +} + +} // namespace vr
diff --git a/chrome/browser/vr/elements/text.h b/chrome/browser/vr/elements/text.h new file mode 100644 index 0000000..9935cb7 --- /dev/null +++ b/chrome/browser/vr/elements/text.h
@@ -0,0 +1,34 @@ +// 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_VR_ELEMENTS_TEXT_H_ +#define CHROME_BROWSER_VR_ELEMENTS_TEXT_H_ + +#include <memory> + +#include "chrome/browser/vr/elements/textured_element.h" + +namespace vr { + +class TextTexture; +class UiTexture; + +class Text : public TexturedElement { + public: + Text(int maximum_width_pixels, + float font_height_meters, + float text_width_meters, + int resource_id); + ~Text() override; + + private: + UiTexture* GetTexture() const override; + + std::unique_ptr<TextTexture> texture_; + DISALLOW_COPY_AND_ASSIGN(Text); +}; + +} // namespace vr + +#endif // CHROME_BROWSER_VR_ELEMENTS_TEXT_H_
diff --git a/chrome/browser/vr/elements/ui_element_debug_id.h b/chrome/browser/vr/elements/ui_element_debug_id.h index 2574541a..04c6ff6f 100644 --- a/chrome/browser/vr/elements/ui_element_debug_id.h +++ b/chrome/browser/vr/elements/ui_element_debug_id.h
@@ -41,6 +41,7 @@ kBackgroundRight, kBackgroundTop, kBackgroundBottom, + kUnderDevelopmentNotice, }; } // namespace vr
diff --git a/chrome/browser/vr/ui_scene_manager.cc b/chrome/browser/vr/ui_scene_manager.cc index 54f20e8..c5b0a2e 100644 --- a/chrome/browser/vr/ui_scene_manager.cc +++ b/chrome/browser/vr/ui_scene_manager.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/vr/elements/screen_dimmer.h" #include "chrome/browser/vr/elements/splash_screen_icon.h" #include "chrome/browser/vr/elements/system_indicator.h" +#include "chrome/browser/vr/elements/text.h" #include "chrome/browser/vr/elements/transient_url_bar.h" #include "chrome/browser/vr/elements/ui_element.h" #include "chrome/browser/vr/elements/ui_element_debug_id.h" @@ -134,6 +135,14 @@ // Tiny distance to offset textures that should appear in the same plane. static constexpr float kTextureOffset = 0.01; +static constexpr float kUnderDevelopmentNoticeFontHeightM = + 0.02f * kUrlBarDistance; +static constexpr float kUnderDevelopmentNoticeHeightM = 0.1f * kUrlBarDistance; +static constexpr float kUnderDevelopmentNoticeWidthM = 0.44f * kUrlBarDistance; +static constexpr float kUnderDevelopmentNoticeVerticalOffsetM = + 0.5f * kUnderDevelopmentNoticeHeightM + kUrlBarHeight; +static constexpr float kUnderDevelopmentNoticeRotationRad = -0.19; + enum DrawPhase : int { kPhaseBackground = 0, kPhaseFloorCeiling, @@ -166,6 +175,7 @@ CreateExitPrompt(); CreateToasts(); CreateSplashScreen(); + CreateUnderDevelopmentNotice(); ConfigureScene(); } @@ -333,6 +343,24 @@ scene_->AddUiElement(std::move(icon)); } +void UiSceneManager::CreateUnderDevelopmentNotice() { + std::unique_ptr<Text> text = base::MakeUnique<Text>( + 512, kUnderDevelopmentNoticeFontHeightM, kUnderDevelopmentNoticeWidthM, + IDS_VR_UNDER_DEVELOPMENT_NOTICE); + text->set_debug_id(kUnderDevelopmentNotice); + text->set_id(AllocateId()); + text->set_draw_phase(kPhaseForeground); + text->set_hit_testable(false); + text->SetSize(kUnderDevelopmentNoticeWidthM, kUnderDevelopmentNoticeHeightM); + text->SetTranslate(0, -kUnderDevelopmentNoticeVerticalOffsetM, 0); + text->SetRotate(1, 0, 0, kUnderDevelopmentNoticeRotationRad); + text->SetEnabled(true); + text->set_y_anchoring(YAnchoring::YBOTTOM); + url_bar_->AddChild(text.get()); + control_elements_.push_back(text.get()); + scene_->AddUiElement(std::move(text)); +} + void UiSceneManager::CreateBackground() { // Background solid-color panels.
diff --git a/chrome/browser/vr/ui_scene_manager.h b/chrome/browser/vr/ui_scene_manager.h index 2fb94de..31767477 100644 --- a/chrome/browser/vr/ui_scene_manager.h +++ b/chrome/browser/vr/ui_scene_manager.h
@@ -77,6 +77,7 @@ void CreateSystemIndicators(); void CreateContentQuad(ContentInputDelegate* delegate); void CreateSplashScreen(); + void CreateUnderDevelopmentNotice(); void CreateBackground(); void CreateUrlBar(); void CreateTransientUrlBar();
diff --git a/chrome/browser/vr/ui_scene_manager_unittest.cc b/chrome/browser/vr/ui_scene_manager_unittest.cc index a8a36bda..d2cb8000 100644 --- a/chrome/browser/vr/ui_scene_manager_unittest.cc +++ b/chrome/browser/vr/ui_scene_manager_unittest.cc
@@ -32,9 +32,10 @@ kBackgroundFront, kBackgroundLeft, kBackgroundBack, kBackgroundRight, kBackgroundTop, kBackgroundBottom, kCeiling, kFloor}; std::set<UiElementDebugId> kElementsVisibleInBrowsing = { - kBackgroundFront, kBackgroundLeft, kBackgroundBack, kBackgroundRight, - kBackgroundTop, kBackgroundBottom, kCeiling, kFloor, - kContentQuad, kBackplane, kUrlBar}; + kBackgroundFront, kBackgroundLeft, kBackgroundBack, + kBackgroundRight, kBackgroundTop, kBackgroundBottom, + kCeiling, kFloor, kContentQuad, + kBackplane, kUrlBar, kUnderDevelopmentNotice}; std::set<UiElementDebugId> kElementsVisibleWithExitPrompt = { kBackgroundFront, kBackgroundLeft, kBackgroundBack, kBackgroundRight, kBackgroundTop, kBackgroundBottom, kCeiling, kFloor,
diff --git a/chrome/browser/web_applications/update_shortcut_worker_win.cc b/chrome/browser/web_applications/update_shortcut_worker_win.cc index 34a1923..9d3ae82 100644 --- a/chrome/browser/web_applications/update_shortcut_worker_win.cc +++ b/chrome/browser/web_applications/update_shortcut_worker_win.cc
@@ -86,10 +86,6 @@ if (unprocessed_icons_.empty()) { // No app icon. Just use the favicon from WebContents. - // TODO(mgiuca): This Image is passed to the FILE thread while still being - // used on the UI thread. This is not thread-safe and needs to be fixed. - // Remove this thread-check disable. https://crbug.com/596348. - shortcut_info_->favicon.DisableThreadChecking(); UpdateShortcuts(); return; }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 2417537a..6f2a856 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -236,7 +236,11 @@ web_contents->GetTitle()) : app_info.title; info->description = app_info.description; - info->favicon.Add(favicon_driver->GetFavicon()); + // Even though GetFavicon returns a gfx::Image, we *deliberately* call + // AsImageSkia to get the internal ImageSkia, then construct a new gfx::Image. + // This ensures the ShortcutInfo's favicon does not share a backing store with + // |web_contents|, which would not be thread safe. https://crbug.com/596348. + info->favicon.Add(favicon_driver->GetFavicon().AsImageSkia()); Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext());
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 695af275..7a341c88 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -131,7 +131,9 @@ ShortcutInfoCallback; #if defined(TOOLKIT_VIEWS) -// Extracts shortcut info of the given WebContents. +// Extracts shortcut info of the given WebContents. The result's |favicon| +// member does *not* share a backing store with |web_contents| (so it is +// safe to use it on another thread). std::unique_ptr<ShortcutInfo> GetShortcutInfoForTab( content::WebContents* web_contents); #endif
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 6719125..3b455db41 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -544,6 +544,9 @@ // A boolean pref set to true if time should be displayed in 24-hour clock. const char kUse24HourClock[] = "settings.clock.use_24hour_clock"; +// A string pref containing Timezone ID for this user. +const char kUserTimezone[] = "settings.timezone"; + // This setting disables manual timezone selection and starts periodic timezone // refresh. const char kResolveTimezoneByGeolocation[] = @@ -2034,6 +2037,10 @@ const char kDebuggingFeaturesRequested[] = "DebuggingFeaturesRequested"; #if defined(OS_CHROMEOS) +// This setting controls initial device timezone that is used before user +// session started. It is controlled by device owner. +const char kSigninScreenTimezone[] = "settings.signin_screen_timezone"; + // This setting starts periodic timezone refresh when not in user session. // (user session is controlled by user profile preference // kResolveTimezoneByGeolocation
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 0bfb05b..f4928d6 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -208,6 +208,7 @@ extern const char kMouseSensitivity[]; extern const char kTouchpadSensitivity[]; extern const char kUse24HourClock[]; +extern const char kUserTimezone[]; extern const char kResolveTimezoneByGeolocation[]; // TODO(yusukes): Change "kLanguageABC" to "kABC". The current form is too long // to remember and confusing. The prefs are actually for input methods and i18n @@ -758,6 +759,7 @@ extern const char kDebuggingFeaturesRequested[]; #if defined(OS_CHROMEOS) +extern const char kSigninScreenTimezone[]; extern const char kResolveDeviceTimezoneByGeolocation[]; extern const char kSystemTimezoneAutomaticDetectionPolicy[]; #endif // defined(OS_CHROMEOS)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 780ebd46..efc312a35 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2936,6 +2936,8 @@ "//testing/scripts/common.py", "//testing/xvfb.py", "//testing/scripts/run_telemetry_as_googletest.py", + # For smoke testing run_telemetry_benchmark_as_googletest + "//testing/scripts/run_telemetry_benchmark_as_googletest.py", ] if (enable_package_mash_services) {
diff --git a/chrome/test/data/webui/settings/date_time_page_tests.js b/chrome/test/data/webui/settings/date_time_page_tests.js index 7a48d13..d6375374 100644 --- a/chrome/test/data/webui/settings/date_time_page_tests.js +++ b/chrome/test/data/webui/settings/date_time_page_tests.js
@@ -13,6 +13,15 @@ value: 'Westeros/Kings_Landing', }, }, + flags: { + // TODO(alemate): This test should be run for both values of this + // option. + per_user_timezone_enabled: { + key: 'cros.flags.per_user_timezone_enabled', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: true, + }, + }, }, settings: { clock: { @@ -27,10 +36,41 @@ type: chrome.settingsPrivate.PrefType.BOOLEAN, value: true, }, + timezone: { + key: 'settings.timezone', + type: chrome.settingsPrivate.PrefType.STRING, + value: 'Westeros/Kings_Landing', + }, }, }; } + function updatePrefsWithPolicy(prefs, managed, valueFromPolicy) { + var prefsCopy = JSON.parse(JSON.stringify(prefs)); + if (managed) { + prefsCopy.settings.resolve_timezone_by_geolocation.controlledBy = + chrome.settingsPrivate.ControlledBy.USER_POLICY; + prefsCopy.settings.resolve_timezone_by_geolocation.enforcement = + chrome.settingsPrivate.Enforcement.ENFORCED; + prefsCopy.settings.resolve_timezone_by_geolocation.value = + valueFromPolicy; + prefsCopy.settings.timezone.controlledBy = + chrome.settingsPrivate.ControlledBy.USER_POLICY; + prefsCopy.settings.timezone.enforcement = + chrome.settingsPrivate.Enforcement.ENFORCED; + } else { + prefsCopy.settings.resolve_timezone_by_geolocation.controlledBy = + undefined; + prefsCopy.settings.resolve_timezone_by_geolocation.enforcement = + undefined; + // Auto-resolve defaults to true. + prefsCopy.settings.resolve_timezone_by_geolocation.value = true; + prefsCopy.settings.timezone.controlledBy = undefined; + prefsCopy.settings.timezone.enforcement = undefined; + } + return prefsCopy; + } + /** * Sets up fakes and creates the date time element. * @param {!Object} prefs @@ -57,10 +97,13 @@ loadTimeData.data = data; var dateTime = document.createElement('settings-date-time-page'); - dateTime.prefs = prefs; + dateTime.prefs = + updatePrefsWithPolicy(prefs, hasPolicy, opt_autoDetectPolicyValue); CrSettingsPrefs.setInitialized(); document.body.appendChild(dateTime); + cr.webUIListenerCallback( + 'time-zone-auto-detect-policy', hasPolicy, opt_autoDetectPolicyValue); return dateTime; } @@ -110,14 +153,24 @@ PolymerTest.clearBody(); }); - function verifyAutoDetectSetting(autoDetect) { - assertEquals(autoDetect, dateTime.$$('settings-dropdown-menu').disabled); - assertEquals(autoDetect, dateTime.$.timeZoneAutoDetect.checked); + function verifyAutoDetectSetting(autoDetect, managed) { + Polymer.dom.flush(); + var selector = dateTime.$$('#userTimeZoneSelector'); + var selectorHidden = selector ? selector.hidden : true; + assertEquals(managed || autoDetect, selectorHidden); + + var checkButton = dateTime.$$('#timeZoneAutoDetect'); + var checkButtonChecked = checkButton ? checkButton.checked : false; + if (!managed) + assertEquals(autoDetect, checkButtonChecked); } function verifyPolicy(policy) { Polymer.dom.flush(); - var indicator = dateTime.$$('cr-policy-indicator'); + var indicator = + dateTime.$$('#timeZoneAutoDetect').$$('cr-policy-pref-indicator'); + if (indicator && indicator.style.display == 'none') + indicator = null; if (policy) { assertTrue(!!indicator); @@ -127,17 +180,31 @@ assertFalse(!!indicator); } - assertEquals(policy, dateTime.$.timeZoneAutoDetect.disabled); + assertEquals( + policy, dateTime.$$('#timeZoneAutoDetect').$$('#control').disabled); } function verifyTimeZonesPopulated(populated) { - var dropdown = dateTime.$$('settings-dropdown-menu'); + Polymer.dom.flush(); + var userTimezoneDropdown = dateTime.$$('#userTimeZoneSelector'); + var systemTimezoneDropdown = dateTime.$$('#systemTimezoneSelector'); + + var dropdown = + userTimezoneDropdown ? userTimezoneDropdown : systemTimezoneDropdown; if (populated) assertEquals(fakeTimeZones.length, dropdown.menuOptions.length); else assertEquals(1, dropdown.menuOptions.length); } + function updatePolicy(dateTime, managed, valueFromPolicy) { + dateTime.prefs = + updatePrefsWithPolicy(dateTime.prefs, managed, valueFromPolicy); + cr.webUIListenerCallback( + 'time-zone-auto-detect-policy', managed, valueFromPolicy); + Polymer.dom.flush(); + } + test('auto-detect on', function(done) { var prefs = getFakePrefs(); dateTime = initializeDateTime(prefs, false); @@ -145,13 +212,13 @@ assertTrue(dateTimePageReadyCalled); assertFalse(getTimeZonesCalled); - verifyAutoDetectSetting(true); + verifyAutoDetectSetting(true, false); verifyTimeZonesPopulated(false); verifyPolicy(false); // Disable auto-detect. - MockInteractions.tap(dateTime.$.timeZoneAutoDetect); - verifyAutoDetectSetting(false); + MockInteractions.tap(dateTime.$$('#timeZoneAutoDetect').$$('#control')); + verifyAutoDetectSetting(false, false); assertTrue(getTimeZonesCalled); setTimeout(function() { @@ -161,22 +228,21 @@ }); test('auto-detect off', function(done) { - var prefs = getFakePrefs(); - prefs.settings.resolve_timezone_by_geolocation.value = false; - dateTime = initializeDateTime(prefs, false); - cr.webUIListenerCallback('time-zone-auto-detect-policy', false); + dateTime = initializeDateTime(getFakePrefs(), false); + dateTime.set( + 'prefs.settings.resolve_timezone_by_geolocation.value', false); assertTrue(dateTimePageReadyCalled); assertTrue(getTimeZonesCalled); - verifyAutoDetectSetting(false); + verifyAutoDetectSetting(false, false); verifyPolicy(false); setTimeout(function() { verifyTimeZonesPopulated(true); // Enable auto-detect. - MockInteractions.tap(dateTime.$.timeZoneAutoDetect); + MockInteractions.tap(dateTime.$$('#timeZoneAutoDetect').$$('#control')); verifyAutoDetectSetting(true); done(); }); @@ -184,25 +250,25 @@ test('auto-detect forced on', function(done) { var prefs = getFakePrefs(); - prefs.settings.resolve_timezone_by_geolocation.value = false; dateTime = initializeDateTime(prefs, true, true); - cr.webUIListenerCallback('time-zone-auto-detect-policy', true, true); + dateTime.set( + 'prefs.settings.resolve_timezone_by_geolocation.value', false); assertTrue(dateTimePageReadyCalled); assertFalse(getTimeZonesCalled); - verifyAutoDetectSetting(true); + verifyAutoDetectSetting(true, true); verifyTimeZonesPopulated(false); verifyPolicy(true); // Cannot disable auto-detect. - MockInteractions.tap(dateTime.$.timeZoneAutoDetect); - verifyAutoDetectSetting(true); + MockInteractions.tap(dateTime.$$('#timeZoneAutoDetect').$$('#control')); + verifyAutoDetectSetting(true, true); assertFalse(getTimeZonesCalled); // Update the policy: force auto-detect off. - cr.webUIListenerCallback('time-zone-auto-detect-policy', true, false); - verifyAutoDetectSetting(false); + updatePolicy(dateTime, true, false); + verifyAutoDetectSetting(false, true); verifyPolicy(true); assertTrue(getTimeZonesCalled); @@ -215,32 +281,30 @@ test('auto-detect forced off', function(done) { var prefs = getFakePrefs(); dateTime = initializeDateTime(prefs, true, false); - cr.webUIListenerCallback('time-zone-auto-detect-policy', true, false); assertTrue(dateTimePageReadyCalled); assertTrue(getTimeZonesCalled); - verifyAutoDetectSetting(false); + verifyAutoDetectSetting(false, true); verifyPolicy(true); setTimeout(function() { verifyTimeZonesPopulated(true); // Remove the policy so user's preference takes effect. - cr.webUIListenerCallback('time-zone-auto-detect-policy', false); - verifyAutoDetectSetting(true); + updatePolicy(dateTime, false); + verifyAutoDetectSetting(true, false); verifyPolicy(false); // User can disable auto-detect. - MockInteractions.tap(dateTime.$.timeZoneAutoDetect); - verifyAutoDetectSetting(false); + MockInteractions.tap(dateTime.$$('#timeZoneAutoDetect').$$('#control')); + verifyAutoDetectSetting(false, false); done(); }); }); test('set date and time button', function() { dateTime = initializeDateTime(getFakePrefs(), false); - cr.webUIListenerCallback('time-zone-auto-detect-policy', false); var showSetDateTimeUICalled = false; registerMessageCallback('showSetDateTimeUI', null, function() { @@ -248,7 +312,7 @@ showSetDateTimeUICalled = true; }); - var setDateTimeButton = dateTime.$.setDateTime; + var setDateTimeButton = dateTime.$$('#setDateTime'); assertEquals(0, setDateTimeButton.offsetHeight); // Make the date and time editable.
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index b1d2ffa4..e900198 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc
@@ -522,6 +522,9 @@ const char kEnterpriseEnableLicenseTypeSelection[] = "enterprise-enable-license-type-selection"; +// Disables per-user timezone. +const char kDisablePerUserTimezone[] = "disable-per-user-timezone"; + bool WakeOnWifiEnabled() { return !base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableWakeOnWifi); }
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index 701cfe4..598ceb0 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h
@@ -149,6 +149,7 @@ CHROMEOS_EXPORT extern const char kCrosGaiaApiV1[]; CHROMEOS_EXPORT extern const char kVoiceInteractionLocales[]; CHROMEOS_EXPORT extern const char kEnterpriseEnableLicenseTypeSelection[]; +CHROMEOS_EXPORT extern const char kDisablePerUserTimezone[]; // Returns true if the system should wake in response to wifi traffic. CHROMEOS_EXPORT bool WakeOnWifiEnabled();
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc index e203881..34a8ebd 100644 --- a/chromeos/settings/cros_settings_names.cc +++ b/chromeos/settings/cros_settings_names.cc
@@ -245,4 +245,7 @@ const char kDeviceLoginScreenInputMethods[] = "cros.device_login_screen_input_methods"; +// A boolean pref that matches enable-per-user-time-zone chrome://flags value. +const char kPerUserTimezoneEnabled[] = "cros.flags.per_user_timezone_enabled"; + } // namespace chromeos
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h index 0034a20e..06dac28d 100644 --- a/chromeos/settings/cros_settings_names.h +++ b/chromeos/settings/cros_settings_names.h
@@ -119,6 +119,8 @@ CHROMEOS_EXPORT extern const char kDeviceLoginScreenLocales[]; CHROMEOS_EXPORT extern const char kDeviceLoginScreenInputMethods[]; +CHROMEOS_EXPORT extern const char kPerUserTimezoneEnabled[]; + } // namespace chromeos #endif // CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/components/metrics/drive_metrics_provider_linux.cc b/components/metrics/drive_metrics_provider_linux.cc index 194e1ee..0ba3a9c 100644 --- a/components/metrics/drive_metrics_provider_linux.cc +++ b/components/metrics/drive_metrics_provider_linux.cc
@@ -34,6 +34,8 @@ bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path, bool* has_seek_penalty) { #if defined(OS_CHROMEOS) + // TODO(derat): Remove special-casing after October 2017 when parrot (Acer C7 + // Chromebook) is unsupported. std::string board = base::SysInfo::GetStrippedReleaseBoard(); // There are "parrot", "parrot_ivb" and "parrot_freon" boards that have // devices with rotating disks. All other ChromeOS devices have SSDs.
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 7f5b9ed..6e98c09 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -333,6 +333,9 @@ WebRuntimeFeatures::EnableMojoBlobs( base::FeatureList::IsEnabled(features::kMojoBlobs)); + WebRuntimeFeatures::EnableNetworkService( + base::FeatureList::IsEnabled(features::kNetworkService)); + if (base::FeatureList::IsEnabled(features::kGamepadExtensions)) WebRuntimeFeatures::EnableGamepadExtensions(true);
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index 223e1a0..ad668dcd 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision 72eda82d069da578af04e5c4e8e411ae006b6a18 +Current webgl revision ca7121e53f7794a60ac2948c34c224ee921a8910
diff --git a/ios/build/xcode_install_wrapper.py b/ios/build/xcode_install_wrapper.py deleted file mode 100755 index b7b53fcb..0000000 --- a/ios/build/xcode_install_wrapper.py +++ /dev/null
@@ -1,75 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -"""Wrapper script to install Xcode. For use on the bots. - -Installing Xcode requires sudo. This script will be whitelisted in /etc/sudoers -so that we can easily update Xcode on our bots. -""" - -import argparse -import hashlib -import logging -import os -import subprocess -import sys - - -# List of sha256 hashes of Xcode package file -# Contents/Resources/Packages/XcodeSystemResources.pkg -WHITELISTED_PACKAGES = [ - # Xcode versions 8A218a-1, 8A218a-2 - '3d948c4bd7c8941478a60aece3cb98ef936a57a4cc1c8f8d5f7eef70d0ebbad1', - # Xcode versions 8B62-1, 8C1002-1 - '21ed3271af2ac7d67c6c09a9481a1fd5bb886950990365bb936dde7585e09061', - # Xcode versions 8E2002-1 - 'ff2377d3976f7acf2adfe5ca91c2e6cc59dd112647efa0bf39e9d9decd2ee1b3', - # Xcode versions 9M136h-1 - '2ec798b123bcfa7f8c0e5618c193ecd26ddce87f2e27f6b5d2fb0720926e5464', - # Xcode versions 9M137d-1 - '6c5f4a2fd6dc477f8f06ccd6f6119da540dd5fe3a6036357dbe9c13d611fc366', -] - -def main(): - logging.basicConfig(level=logging.DEBUG) - - parser = argparse.ArgumentParser( - description='Wrapper script to install Xcode.') - parser.add_argument( - '--package-path', - help='Path to Xcode package to install.', - required=True) - args = parser.parse_args() - - if not os.path.isfile(args.package_path): - logging.critical('Path %s is not a file.' % args.package_path) - return 1 - - sha256 = hashlib.sha256() - with open(args.package_path, 'rb') as f: - for chunk in iter(lambda: f.read(8192), b''): - sha256.update(chunk) - sha256_hash = sha256.hexdigest() - - if sha256_hash not in WHITELISTED_PACKAGES: - logging.critical('Attempted to install a non-whitelisted Xcode package.') - return 1 - - pipe = subprocess.Popen( - ['/usr/sbin/installer', '-pkg', args.package_path, '-target', '/'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = pipe.communicate() - - for line in stdout.splitlines(): - logging.debug(line) - for line in stderr.splitlines(): - logging.error(line) - - return pipe.returncode - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index f0f2e762..ced6324 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -2051,9 +2051,18 @@ if (result > 0) { read_offset_ += result; } else if (result == 0) { // End of file. - RecordHistograms(); - cache_->DoneReadingFromEntry(entry_, this); - entry_ = NULL; + // TODO(shivanisha@), ideally it should not happen that |this| is not a + // reader but referenced from entry in another field, but it seems to be + // happening in some edge case (crbug.com/752774). Thus not invoking + // DoneReadingFromEntry here. + if (entry_->writer == this) { + DoneWritingToEntry(true); + } else { + RecordHistograms(); + cache_->DoneWithEntry(entry_, this, false /* process_cancel */, + partial_ != nullptr); + entry_ = NULL; + } } else { return OnCacheReadError(result, false); }
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc index 80daed7..18c303a9 100644 --- a/printing/backend/cups_jobs.cc +++ b/printing/backend/cups_jobs.cc
@@ -395,6 +395,8 @@ ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD, kRequestedAttributes, num_attributes, nullptr, attributes); + DCHECK_EQ(ippValidateAttributes(request.get()), 1); + auto response = WrapIpp(cupsDoRequest(http, request.release(), rp.c_str())); *status = ippGetStatusCode(response.get()); @@ -427,12 +429,14 @@ bool GetPrinterInfo(const std::string& address, const int port, const std::string& resource, + bool encrypted, PrinterInfo* printer_info) { base::ThreadRestrictions::AssertIOAllowed(); - ScopedHttpPtr http = ScopedHttpPtr( - httpConnect2(address.data(), port, nullptr, AF_INET, - HTTP_ENCRYPTION_IF_REQUESTED, 0, 200, nullptr)); + ScopedHttpPtr http = ScopedHttpPtr(httpConnect2( + address.data(), port, nullptr, AF_INET, + encrypted ? HTTP_ENCRYPTION_REQUIRED : HTTP_ENCRYPTION_IF_REQUESTED, 0, + 200, nullptr)); if (!http) { LOG(WARNING) << "Could not connect to host"; return false;
diff --git a/printing/backend/cups_jobs.h b/printing/backend/cups_jobs.h index 8c0e4d4b..c2606eb 100644 --- a/printing/backend/cups_jobs.h +++ b/printing/backend/cups_jobs.h
@@ -153,10 +153,12 @@ void ParsePrinterStatus(ipp_t* response, PrinterStatus* printer_status); // Queries the printer at |address| on |port| with a Get-Printer-Attributes -// request to populate |printer_info|. Returns false if the request failed. +// request to populate |printer_info|. If |encrypted| is true, request is made +// using ipps, otherwise, ipp is used. Returns false if the request failed. bool PRINTING_EXPORT GetPrinterInfo(const std::string& address, const int port, const std::string& resource, + bool encrypted, PrinterInfo* printer_info); // Attempts to retrieve printer status using connection |http| for |printer_id|.
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 19d9833b..7f2de04 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -13650,14 +13650,28 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Mac-10.12" + "gpu": "8086:0d26", + "hidpi": "1", + "os": "Mac-10.11.6" + }, + { + "gpu": "none", + "os": "Mac-10.9.5" + }, + { + "gpu": "none", + "os": "Mac-10.10.5" + }, + { + "gpu": "none", + "os": "Mac-10.11.6" }, { "gpu": "8086:0a2e", - "os": "Mac-10.12" + "os": "Mac-10.12.5" } ], - "shards": 8 + "shards": 2 } } ]
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-transform-responsive-expected.html similarity index 100% rename from third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive-expected.html rename to third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-transform-responsive-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-transform-responsive.html similarity index 100% rename from third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive.html rename to third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-transform-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive-expected.html new file mode 100644 index 0000000..853c7b5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive-expected.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<style> +#target { + position: absolute; + width: 100px; + height: 100px; + background: blue; + translate: calc(50vw - 50px) calc(50vh - 50px); +} +</style> +This box should be located in the center of the page. +<div id="target"></div> +<script> +if (window.testRunner) { + testRunner.useUnfortunateSynchronousResizeMode(); +} +window.resizeTo(window.innerWidth / 2, window.innerHeight / 2); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive.html new file mode 100644 index 0000000..2bc9f10 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-translate-responsive.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<style> +#target { + position: absolute; + width: 100px; + height: 100px; + background: blue; +} +</style> +This box should be located in the center of the page. +<div id="target"></div> +<script> +if (window.testRunner) { + testRunner.useUnfortunateSynchronousResizeMode(); + testRunner.waitUntilDone(); +} +function waitForCompositor() { + return document.body.animate({opacity: [1, 1]}, 1).finished; +} + +var position = 'calc(50vw - 50px) calc(50vh - 50px)'; +var animation = target.animate({translate: [position, position]}, 1e10); +animation.ready.then(() => { + window.resizeTo(window.innerWidth / 2, window.innerHeight / 2); +}).then(waitForCompositor).then(() => { + if (window.testRunner) { + testRunner.notifyDone(); + } +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation-expected.html new file mode 100644 index 0000000..8cbd2baa --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation-expected.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<style> +#container { + position: absolute; + top: 0; + font-size: 10px; +} +.target { + width: 40px; + height: 40px; + border-top: solid; + border-left: solid; + margin-bottom: 20px; +} +</style> +<div id="container"></div> +<div id="footer"></div> +<script> +'use strict'; +internals.setZoomFactor(2); + +[ + '10px 10px 10px', + 'none', // Composited animations fail to zoom the last expectation correctly. ): +].forEach(translation => { + var text = document.createElement('div'); + text.textContent = translation; + container.appendChild(text); + + var target = document.createElement('div'); + target.classList.add('target'); + container.appendChild(target); + target.animate([ + {translate: translation}, + {translate: translation}, + ], 1e8); +}); + +// We must wait a frame to let compositor animations render. +if (window.testRunner) + testRunner.waitUntilDone(); + +function waitForCompositor() { + return footer.animate({opacity: ['1', '1']}, 1).finished; +} + +requestAnimationFrame(() => { + requestAnimationFrame(() => { + waitForCompositor().then(() => { + if (window.testRunner) + testRunner.notifyDone(); + }); + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation.html b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation.html new file mode 100644 index 0000000..3b8b5a31 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-translate-animation.html
@@ -0,0 +1,57 @@ +<!DOCTYPE html> +<style> +#container { + position: absolute; + top: 0; + font-size: 10px; +} +.target { + width: 40px; + height: 40px; + border-top: solid; + border-left: solid; + margin-bottom: 20px; +} +</style> +<div id="container"></div> +<div id="footer"></div> +<script> +'use strict'; +[ + '10px 10px 10px', + 'none', // Composited animations fail to zoom the last expectation correctly. ): +].forEach(translation => { + var text = document.createElement('div'); + text.textContent = translation; + container.appendChild(text); + + var target = document.createElement('div'); + target.classList.add('target'); + container.appendChild(target); + target.animate([ + {translate: translation}, + {translate: translation}, + ], 1e8); +}); + +if (window.testRunner) + testRunner.waitUntilDone(); + +function waitForCompositor() { + return footer.animate({opacity: ['1', '1']}, 1).finished; +} + +requestAnimationFrame(() => { + requestAnimationFrame(() => { + internals.setZoomFactor(2); + requestAnimationFrame(() => { + requestAnimationFrame(() => { + waitForCompositor().then(() => { + if (window.testRunner) + testRunner.notifyDone(); + }); + }); + }); + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/resources/interpolation-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/resources/interpolation-testcommon.js new file mode 100644 index 0000000..5ab5551 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/resources/interpolation-testcommon.js
@@ -0,0 +1,54 @@ +'use strict'; +function test_interpolation(settings, expectations) { + // Returns a timing function that at 0.5 evaluates to progress. + function timingFunction(progress) { + if (progress === 0) + return 'steps(1, end)'; + if (progress === 1) + return 'steps(1, start)'; + var y = (8 * progress - 1) / 6; + return 'cubic-bezier(0, ' + y + ', 1, ' + y + ')'; + } + + test(function(){ + assert_true(CSS.supports(settings.property, settings.from), 'Value "' + settings.from + '" is supported by ' + settings.property); + assert_true(CSS.supports(settings.property, settings.to), 'Value "' + settings.to + '" is supported by ' + settings.property); + }, '"' + settings.from + '" and "' + settings.to + '" are valid ' + settings.property + ' values'); + + for (var i = 0; i < expectations.length; ++i) { + var progress = expectations[i].at; + var expectation = expectations[i].expect; + var animationId = 'anim' + i; + var targetId = 'target' + i; + var referenceId = 'reference' + i; + + test(function(){ + assert_true(CSS.supports(settings.property, expectation), 'Value "' + expectation + '" is supported by ' + settings.property); + + var stylesheet = document.createElement('style'); + stylesheet.textContent = + '#' + targetId + ' {\n' + + ' animation: 2s ' + timingFunction(progress) + ' -1s paused ' + animationId + ';\n' + + '}\n' + + '@keyframes ' + animationId + ' {\n' + + ' 0% { ' + settings.property + ': ' + settings.from + '; }\n' + + ' 100% { ' + settings.property + ': ' + settings.to + '; }\n' + + '}\n' + + '#' + referenceId + ' {\n' + + ' ' + settings.property + ': ' + expectation + ';\n' + + '}\n'; + document.head.appendChild(stylesheet); + + var target = document.createElement('div'); + target.id = targetId; + document.body.appendChild(target); + + var reference = document.createElement('div'); + reference.id = referenceId; + document.body.appendChild(reference); + reference.style = ''; + + assert_equals(getComputedStyle(target)[settings.property], getComputedStyle(reference)[settings.property]); + }, 'Animation between "' + settings.from + '" and "' + settings.to + '" at progress ' + progress); + } +}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/rotate-interpolation.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/rotate-interpolation.html new file mode 100644 index 0000000..ec96ba0b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/rotate-interpolation.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>rotate interpolation</title> + <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> + <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-rotate"> + <meta name="assert" content="rotate supports animation."> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/interpolation-testcommon.js"></script> + </head> + <body> + <script> + test_interpolation({ + property: 'rotate', + from: '100deg', + to: '180deg', + }, [ + {at: -1, expect: '20deg'}, + {at: 0, expect: '100deg'}, + {at: 0.125, expect: '110deg'}, + {at: 0.875, expect: '170deg'}, + {at: 1, expect: '180deg'}, + {at: 2, expect: '260deg'} + ]); + + test_interpolation({ + property: 'rotate', + from: '45deg', + to: '-1 1 0 60deg', + }, [ + {at: -1, expect: '0.447214 -0.447214 0.774597 104.478deg'}, + {at: 0, expect: '45deg'}, + {at: 0.125, expect: '-0.136456 0.136456 0.981203 40.6037deg'}, + {at: 0.875, expect: '-0.70246 0.70246 0.114452 53.1994deg'}, + {at: 1, expect: '-1 1 0 60deg'}, + {at: 2, expect: '-0.637897 0.637897 -0.431479 124.975deg'} + ]); + + test_interpolation({ + property: 'rotate', + from: 'none', + to: '7 -8 9 400grad', + }, [ + {at: -1, expect: '7 -8 9 -400grad'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: '7 -8 9 50grad'}, + {at: 0.875, expect: '7 -8 9 350grad'}, + {at: 1, expect: '7 -8 9 400grad'}, + {at: 2, expect: '7 -8 9 800grad'} + ]); + + test_interpolation({ + property: 'rotate', + from: 'none', + to: 'none', + }, [ + {at: -1, expect: 'none'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: 'none'}, + {at: 0.875, expect: 'none'}, + {at: 1, expect: 'none'}, + {at: 2, expect: 'none'} + ]); + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/scale-interpolation.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/scale-interpolation.html new file mode 100644 index 0000000..da25d3a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/scale-interpolation.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>scale interpolation</title> + <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> + <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-scale"> + <meta name="assert" content="scale supports animation."> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/interpolation-testcommon.js"></script> + </head> + <body> + <script> + test_interpolation({ + property: 'scale', + from: '2 30 400', + to: '10 110 1200', + }, [ + {at: -1, expect: '-6 -50 -400'}, + {at: 0, expect: '2 30 400'}, + {at: 0.125, expect: '3 40 500'}, + {at: 0.875, expect: '9 100 1100'}, + {at: 1, expect: '10 110 1200'}, + {at: 2, expect: '18 190 2000'} + ]); + + test_interpolation({ + property: 'scale', + from: '26 17 9', + to: '2', + }, [ + {at: -1, expect: '50 33 17'}, + {at: 0, expect: '26 17 9'}, + {at: 0.125, expect: '23 15 8'}, + {at: 0.875, expect: '5 3 2'}, + {at: 1, expect: '2'}, + {at: 2, expect: '-22 -15 -7'} + ]); + + test_interpolation({ + property: 'scale', + from: 'none', + to: '4 3 2', + }, [ + {at: -1, expect: '-2 -1 0'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: '1.375 1.25 1.125'}, + {at: 0.875, expect: '3.625 2.75 1.875'}, + {at: 1, expect: '4 3 2'}, + {at: 2, expect: '7 5 3'} + ]); + + test_interpolation({ + property: 'scale', + from: 'none', + to: 'none', + }, [ + {at: -1, expect: 'none'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: 'none'}, + {at: 0.875, expect: 'none'}, + {at: 1, expect: 'none'}, + {at: 2, expect: 'none'} + ]); + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/translate-interpolation.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/translate-interpolation.html new file mode 100644 index 0000000..d5d47f7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/animation/translate-interpolation.html
@@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>translate interpolation</title> + <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> + <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-translate"> + <meta name="assert" content="translate supports <length> and <percentage> animation."> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/interpolation-testcommon.js"></script> + <style> + body { + width: 500px; + height: 500px; + } + div { + width: 10px; + height: 10px; + } + </style> + </head> + <body> + <script> + test_interpolation({ + property: 'translate', + from: '220px 240px 260px', + to: '300px 400px 500px', + }, [ + {at: -1, expect: '140px 80px 20px'}, + {at: 0, expect: '220px 240px 260px'}, + {at: 0.125, expect: '230px 260px 290px'}, + {at: 0.875, expect: '290px 380px 470px'}, + {at: 1, expect: '300px 400px 500px'}, + {at: 2, expect: '380px 560px 740px'} + ]); + + test_interpolation({ + property: 'translate', + from: '480px 400px 320px', + to: '240% 160%', + }, [ + {at: -1, expect: 'calc(960px - 240%) calc(800px - 160%) 640px'}, + {at: 0, expect: '480px 400px 320px'}, + {at: 0.125, expect: 'calc(420px + 30%) calc(350px + 20%) 280px'}, + {at: 0.875, expect: 'calc(210% + 60px) calc(140% + 50px) 40px'}, + {at: 1, expect: '240% 160%'}, + {at: 2, expect: 'calc(480% - 480px) calc(320% - 400px) -320px'} + ]); + + test_interpolation({ + property: 'translate', + from: 'none', + to: '8px 80% 800px', + }, [ + {at: -1, expect: '-8px -80% -800px'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: '1px 10% 100px'}, + {at: 0.875, expect: '7px 70% 700px'}, + {at: 1, expect: '8px 80% 800px'}, + {at: 2, expect: '16px 160% 1600px'} + ]); + + test_interpolation({ + property: 'translate', + from: 'none', + to: 'none', + }, [ + {at: -1, expect: 'none'}, + {at: 0, expect: 'none'}, + {at: 0.125, expect: 'none'}, + {at: 0.875, expect: 'none'}, + {at: 1, expect: 'none'}, + {at: 2, expect: 'none'} + ]); + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/mojo/bind-interface.html b/third_party/WebKit/LayoutTests/mojo/bind-interface.html index eaa08c3..26c4867 100644 --- a/third_party/WebKit/LayoutTests/mojo/bind-interface.html +++ b/third_party/WebKit/LayoutTests/mojo/bind-interface.html
@@ -77,25 +77,41 @@ return Promise.reject(); }, "interface interceptors are mutually exclusive"); -test(() => { +test(async t => { const kTestInterfaceName = "foo::mojom::Bar"; - let interceptedHandle = null; + // First check that the interceptor can be started and intercepts requests. let interceptor = new MojoInterfaceInterceptor(kTestInterfaceName); - interceptor.oninterfacerequest = e => { interceptedHandle = e.handle; }; + let promise = new Promise(resolve => { + interceptor.oninterfacerequest = e => { + resolve(e.handle); + }; + }); interceptor.start(); - let {handle0, handle1} = Mojo.createMessagePipe(); - Mojo.bindInterface(kTestInterfaceName, handle0); - interceptor.stop(); - + let pipe = Mojo.createMessagePipe(); + Mojo.bindInterface(kTestInterfaceName, pipe.handle0); + let interceptedHandle = await promise; assert_true(interceptedHandle instanceof MojoHandle); interceptedHandle.close(); - interceptedHandle = null; + pipe.handle1.close(); - Mojo.bindInterface(kTestInterfaceName, handle1); - assert_equals(interceptedHandle, null); - handle1.close(); + // Stop the interceptor and make another request. + interceptor.stop(); + + pipe = Mojo.createMessagePipe(); + interceptor.oninterfacerequest = t.step_func(() => { + assert_unreached("unexpected 'interfacerequest' event after stop"); + }); + promise = new Promise(resolve => { + let watcher = pipe.handle1.watch({peerClosed: true}, () => { + watcher.cancel(); // Necessary to avoid a DCHECK when handle1 is closed. + resolve(); + }); + }); + Mojo.bindInterface(kTestInterfaceName, pipe.handle0); + await promise; + pipe.handle1.close(); interceptor = new MojoInterfaceInterceptor(kTestInterfaceName); interceptor.oninterfacerequest = e => {};
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp index 09352d9..1e9bcec 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -265,7 +265,8 @@ bool update_compositor_keyframes = false; if ((transform_zoom_changed || was_viewport_resized) && - keyframe_effect->Affects(PropertyHandle(CSSPropertyTransform)) && + (keyframe_effect->Affects(PropertyHandle(CSSPropertyTransform)) || + keyframe_effect->Affects(PropertyHandle(CSSPropertyTranslate))) && keyframe_effect->SnapshotAllCompositorKeyframes(element, style, parent_style)) { update_compositor_keyframes = true;
diff --git a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp index 3e930b7..e570adee 100644 --- a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp +++ b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp
@@ -7,6 +7,7 @@ #include "bindings/core/v8/ExceptionState.h" #include "core/dom/Document.h" #include "core/dom/ExecutionContext.h" +#include "core/dom/TaskRunnerHelper.h" #include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalFrame.h" #include "core/frame/LocalFrameClient.h" @@ -14,6 +15,7 @@ #include "core/mojo/test/MojoInterfaceRequestEvent.h" #include "core/workers/WorkerGlobalScope.h" #include "core/workers/WorkerThread.h" +#include "platform/WebTaskRunner.h" #include "platform/bindings/ScriptState.h" #include "platform/wtf/text/StringUTF8Adaptor.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -118,6 +120,20 @@ void MojoInterfaceInterceptor::OnInterfaceRequest( mojo::ScopedMessagePipeHandle handle) { + // Execution of JavaScript may be forbidden in this context as this method is + // called synchronously by the InterfaceProvider. Dispatching of the + // 'interfacerequest' event is therefore scheduled to take place in the next + // microtask. This also more closely mirrors the behavior when an interface + // request is being satisfied by another process. + TaskRunnerHelper::Get(TaskType::kMicrotask, GetExecutionContext()) + ->PostTask( + BLINK_FROM_HERE, + WTF::Bind(&MojoInterfaceInterceptor::DispatchInterfaceRequestEvent, + WrapPersistent(this), WTF::Passed(std::move(handle)))); +} + +void MojoInterfaceInterceptor::DispatchInterfaceRequestEvent( + mojo::ScopedMessagePipeHandle handle) { DispatchEvent(MojoInterfaceRequestEvent::Create( MojoHandle::Create(mojo::ScopedHandle::From(std::move(handle))))); }
diff --git a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h index ff73826..9877b32a 100644 --- a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h +++ b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h
@@ -65,6 +65,7 @@ service_manager::InterfaceProvider* GetInterfaceProvider() const; void OnInterfaceRequest(mojo::ScopedMessagePipeHandle); + void DispatchInterfaceRequestEvent(mojo::ScopedMessagePipeHandle); const String interface_name_; bool started_ = false;
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index efea764..9376e9a 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -1083,7 +1083,9 @@ // When responseType is set to "blob", we redirect the downloaded data to a // file-handle directly. - downloading_to_file_ = GetResponseTypeCode() == kResponseTypeBlob; + // TODO: implement this for network service code path. http://crbug.com/754493 + if (!RuntimeEnabledFeatures::NetworkServiceEnabled()) + downloading_to_file_ = GetResponseTypeCode() == kResponseTypeBlob; if (downloading_to_file_) { request.SetDownloadToFile(true); resource_loader_options.data_buffering_policy = kDoNotBufferData;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 index 80cba1e0..43d271e3 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -710,6 +710,9 @@ name: "NetInfoRtt", status: "stable", }, + { + name: "NetworkService", + }, // Not a web exposed feature, enabled from the command line. { name: "NewRemotePlaybackPipeline",
diff --git a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp index 5af69d5c..d2eac73 100644 --- a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp +++ b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
@@ -208,6 +208,10 @@ RuntimeEnabledFeatures::SetNetInfoDownlinkMaxEnabled(enable); } +void WebRuntimeFeatures::EnableNetworkService(bool enable) { + RuntimeEnabledFeatures::SetNetworkServiceEnabled(enable); +} + void WebRuntimeFeatures::EnableOffMainThreadFetch(bool enable) { RuntimeEnabledFeatures::SetOffMainThreadFetchEnabled(enable); }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp index 0d7ebea..844aa27 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -798,15 +798,11 @@ scroll_node.main_thread_scrolling_reasons); auto* layer = ContentLayerAt(0); + auto transform_node_index = layer->transform_tree_index(); + EXPECT_EQ(transform_node_index, transform_node.id); auto scroll_node_index = layer->scroll_tree_index(); EXPECT_EQ(scroll_node_index, scroll_node.id); - // Only one content layer, and the first child layer is the dummy layer for - // the transform node. - const cc::Layer* transform_node_layer = RootLayer()->children()[0].get(); - auto transform_node_index = transform_node_layer->transform_tree_index(); - EXPECT_EQ(transform_node_index, transform_node.id); - EXPECT_EQ(0u, scroll_client.did_scroll_count); // TODO(pdr): The PaintArtifactCompositor should set the scrolling content // bounds so the Layer is scrollable. This call should be removed. @@ -1715,31 +1711,6 @@ ElementIdToTransformNodeIndex(transform->GetCompositorElementId())); } -TEST_F(PaintArtifactCompositorTestWithPropertyTrees, - TransformNodeHasOwningLayerId) { - RefPtr<TransformPaintPropertyNode> transform = - TransformPaintPropertyNode::Create( - TransformPaintPropertyNode::Root(), TransformationMatrix().Rotate(90), - FloatPoint3D(100, 100, 0), false, 0, kCompositingReason3DTransform); - - TestPaintArtifact artifact; - artifact - .Chunk(transform, ClipPaintPropertyNode::Root(), - EffectPaintPropertyNode::Root()) - .RectDrawing(FloatRect(100, 100, 200, 100), Color::kBlack); - Update(artifact.Build()); - - // Only one content layer, and the first child layer is the dummy layer for - // the transform node. - ASSERT_EQ(1u, ContentLayerCount()); - const cc::Layer* transform_node_layer = RootLayer()->children()[0].get(); - const cc::TransformNode* cc_transform_node = - GetPropertyTrees().transform_tree.Node( - transform_node_layer->transform_tree_index()); - auto transform_node_index = transform_node_layer->transform_tree_index(); - EXPECT_EQ(transform_node_index, cc_transform_node->id); -} - TEST_F(PaintArtifactCompositorTestWithPropertyTrees, EffectWithElementId) { RefPtr<EffectPaintPropertyNode> effect = CreateSampleEffectNodeWithElementId(); @@ -1826,7 +1797,7 @@ // Two content layers for the differentiated rect drawings and three dummy // layers for each of the transform, clip and effect nodes. - EXPECT_EQ(5u, RootLayer()->children().size()); + EXPECT_EQ(2u, RootLayer()->children().size()); int sequence_number = GetPropertyTrees().sequence_number; EXPECT_GT(sequence_number, 0); for (auto layer : RootLayer()->children()) { @@ -1835,7 +1806,7 @@ Update(artifact.Build()); - EXPECT_EQ(5u, RootLayer()->children().size()); + EXPECT_EQ(2u, RootLayer()->children().size()); sequence_number++; EXPECT_EQ(sequence_number, GetPropertyTrees().sequence_number); for (auto layer : RootLayer()->children()) { @@ -1844,7 +1815,7 @@ Update(artifact.Build()); - EXPECT_EQ(5u, RootLayer()->children().size()); + EXPECT_EQ(2u, RootLayer()->children().size()); sequence_number++; EXPECT_EQ(sequence_number, GetPropertyTrees().sequence_number); for (auto layer : RootLayer()->children()) { @@ -2344,27 +2315,26 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // l2 - // l1 [ mask_effect_0 ] - // (l0) [ mask_isolation_0 ] - // [ e0 ] - // One content layer, one dummy, one clip mask. - ASSERT_EQ(3u, RootLayer()->children().size()); + // l1 + // l0 [ mask_effect_0 ] + // [ mask_isolation_0 ] + // [ e0 ] + // One content layer, one clip mask. + ASSERT_EQ(2u, RootLayer()->children().size()); ASSERT_EQ(1u, ContentLayerCount()); ASSERT_EQ(1u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[2].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[1].get(); + constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); @@ -2403,44 +2373,40 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // l4 - // l1 (l2) l3 [ mask_effect_0 ] - // (l0) [ mask_isolation_0 ] - // [ e0 ] - // Two content layers, two dummy, one clip mask. - ASSERT_EQ(5u, RootLayer()->children().size()); + // l2 + // l0 l1 [ mask_effect_0 ] + // [ mask_isolation_0 ] + // [ e0 ] + // Two content layers, one clip mask. + ASSERT_EQ(3u, RootLayer()->children().size()); ASSERT_EQ(2u, ContentLayerCount()); ASSERT_EQ(1u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* dummy_t1 = RootLayer()->children()[2].get(); - const cc::Layer* content1 = RootLayer()->children()[3].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[4].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* content1 = RootLayer()->children()[1].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[2].get(); constexpr int t0_id = 1; + constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); EXPECT_EQ(t0_id, content0->transform_tree_index()); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); ASSERT_EQ(e0_id, mask_isolation_0.parent_id); EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode); - int t1_id = dummy_t1->transform_tree_index(); + EXPECT_EQ(ContentLayerAt(1), content1); + int t1_id = content1->transform_tree_index(); const cc::TransformNode& cc_t1 = *GetPropertyTrees().transform_tree.Node(t1_id); ASSERT_EQ(t0_id, cc_t1.parent_id); - - EXPECT_EQ(ContentLayerAt(1), content1); - EXPECT_EQ(t1_id, content1->transform_tree_index()); EXPECT_EQ(c1_id, content1->clip_tree_index()); EXPECT_EQ(mask_isolation_0_id, content1->effect_tree_index()); @@ -2480,45 +2446,37 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // l3 l6 - // l1 (l2) [ mask_effect_0 ] l5 [ mask_effect_1 ] - // (l0) [ mask_isolation_0 ] l4 [ mask_isolation_1 ] - // [ e0 ] - // Three content layers, two dummy, two clip mask. - ASSERT_EQ(7u, RootLayer()->children().size()); + // l1 l4 + // l0 [ mask_effect_0 ] l3 [ mask_effect_1 ] + // [ mask_isolation_0 ] l2 [ mask_isolation_1 ] + // [ e0 ] + // Three content layers, two clip mask. + ASSERT_EQ(5u, RootLayer()->children().size()); ASSERT_EQ(3u, ContentLayerCount()); ASSERT_EQ(2u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* dummy_t1 = RootLayer()->children()[2].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[3].get(); - const cc::Layer* content1 = RootLayer()->children()[4].get(); - const cc::Layer* content2 = RootLayer()->children()[5].get(); - const cc::Layer* clip_mask1 = RootLayer()->children()[6].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[1].get(); + const cc::Layer* content1 = RootLayer()->children()[2].get(); + const cc::Layer* content2 = RootLayer()->children()[3].get(); + const cc::Layer* clip_mask1 = RootLayer()->children()[4].get(); constexpr int t0_id = 1; constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); EXPECT_EQ(t0_id, content0->transform_tree_index()); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); ASSERT_EQ(e0_id, mask_isolation_0.parent_id); EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode); - int t1_id = dummy_t1->transform_tree_index(); - const cc::TransformNode& cc_t1 = - *GetPropertyTrees().transform_tree.Node(t1_id); - ASSERT_EQ(t0_id, cc_t1.parent_id); - EXPECT_EQ(SynthesizedClipLayerAt(0), clip_mask0); EXPECT_EQ(gfx::Size(300, 200), clip_mask0->bounds()); EXPECT_EQ(t0_id, clip_mask0->transform_tree_index()); @@ -2530,7 +2488,10 @@ EXPECT_EQ(SkBlendMode::kDstIn, mask_effect_0.blend_mode); EXPECT_EQ(ContentLayerAt(1), content1); - EXPECT_EQ(t1_id, content1->transform_tree_index()); + int t1_id = content1->transform_tree_index(); + const cc::TransformNode& cc_t1 = + *GetPropertyTrees().transform_tree.Node(t1_id); + ASSERT_EQ(t0_id, cc_t1.parent_id); EXPECT_EQ(c0_id, content1->clip_tree_index()); EXPECT_EQ(e0_id, content1->effect_tree_index()); @@ -2579,43 +2540,39 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // (l2) l3 l5 - // l1 [ e1 ] l4 [ mask_effect_0 ] - // (l0) [ mask_isolation_0 ] - // [ e0 ] - // Three content layers, two dummy, one clip mask. - ASSERT_EQ(6u, RootLayer()->children().size()); + // l1 l3 + // l0 [ e1 ] l2 [ mask_effect_0 ] + // [ mask_isolation_0 ] + // [ e0 ] + // Three content layers, one clip mask. + ASSERT_EQ(4u, RootLayer()->children().size()); ASSERT_EQ(3u, ContentLayerCount()); ASSERT_EQ(1u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* dummy_e1 = RootLayer()->children()[2].get(); - const cc::Layer* content1 = RootLayer()->children()[3].get(); - const cc::Layer* content2 = RootLayer()->children()[4].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[5].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* content1 = RootLayer()->children()[1].get(); + const cc::Layer* content2 = RootLayer()->children()[2].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[3].get(); + constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); ASSERT_EQ(e0_id, mask_isolation_0.parent_id); EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode); - int e1_id = dummy_e1->effect_tree_index(); - const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); - ASSERT_EQ(mask_isolation_0_id, cc_e1.parent_id); - EXPECT_EQ(ContentLayerAt(1), content1); EXPECT_EQ(c1_id, content1->clip_tree_index()); - EXPECT_EQ(e1_id, content1->effect_tree_index()); + int e1_id = content1->effect_tree_index(); + const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); + ASSERT_EQ(mask_isolation_0_id, cc_e1.parent_id); EXPECT_EQ(ContentLayerAt(2), content2); EXPECT_EQ(c1_id, content2->clip_tree_index()); @@ -2658,33 +2615,31 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // l5 - // l2 l4 [ mask_effect_1 ] l7 - // l1 [ mask_effect_0 ] (l3) [ mask_isolation_1 ] l6 [ mask_effect_2 ] - // (l0) [ mask_isolation_0 ][ e1 ][ mask_isolation_2 ] - // [ e0 ] - // Three content layers, two dummy, three clip mask. - ASSERT_EQ(8u, RootLayer()->children().size()); + // l3 + // l1 l2 [ mask_effect_1 ] l5 + // l0 [ mask_effect_0 ][ mask_isolation_1 ] l4 [ mask_effect_2 ] + // [ mask_isolation_0 ][ e1 ][ mask_isolation_2 ] + // [ e0 ] + // Three content layers, three clip mask. + ASSERT_EQ(6u, RootLayer()->children().size()); ASSERT_EQ(3u, ContentLayerCount()); ASSERT_EQ(3u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[2].get(); - const cc::Layer* dummy_e1 = RootLayer()->children()[3].get(); - const cc::Layer* content1 = RootLayer()->children()[4].get(); - const cc::Layer* clip_mask1 = RootLayer()->children()[5].get(); - const cc::Layer* content2 = RootLayer()->children()[6].get(); - const cc::Layer* clip_mask2 = RootLayer()->children()[7].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[1].get(); + const cc::Layer* content1 = RootLayer()->children()[2].get(); + const cc::Layer* clip_mask1 = RootLayer()->children()[3].get(); + const cc::Layer* content2 = RootLayer()->children()[4].get(); + const cc::Layer* clip_mask2 = RootLayer()->children()[5].get(); + constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); @@ -2700,18 +2655,16 @@ ASSERT_EQ(mask_isolation_0_id, mask_effect_0.parent_id); EXPECT_EQ(SkBlendMode::kDstIn, mask_effect_0.blend_mode); - int e1_id = dummy_e1->effect_tree_index(); - const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); - ASSERT_EQ(e0_id, cc_e1.parent_id); - EXPECT_EQ(ContentLayerAt(1), content1); EXPECT_EQ(c1_id, content1->clip_tree_index()); int mask_isolation_1_id = content1->effect_tree_index(); const cc::EffectNode& mask_isolation_1 = *GetPropertyTrees().effect_tree.Node(mask_isolation_1_id); EXPECT_NE(mask_isolation_0_id, mask_isolation_1_id); - ASSERT_EQ(e1_id, mask_isolation_1.parent_id); EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_1.blend_mode); + int e1_id = mask_isolation_1.parent_id; + const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); + ASSERT_EQ(e0_id, cc_e1.parent_id); EXPECT_EQ(SynthesizedClipLayerAt(1), clip_mask1); EXPECT_EQ(gfx::Size(300, 200), clip_mask1->bounds()); @@ -2767,32 +2720,30 @@ Update(artifact.Build()); // Expectation in effect stack diagram: - // l2 (l3) l4 l5 l7 - // l1 [ mask_effect_0 ][ e1 ][ mask_effect_1 ] l6 [ mask_effect_2 ] - // (l0) [ mask_isolation_0 ][ mask_isolation_1 ][ mask_isolation_2 ] - // [ e0 ] - // Three content layers, two dummy, three clip mask. - ASSERT_EQ(8u, RootLayer()->children().size()); + // l1 l2 l3 l5 + // l0 [ mask_effect_0 ][ e1 ][ mask_effect_1 ] l4 [ mask_effect_2 ] + // [ mask_isolation_0 ][ mask_isolation_1 ][ mask_isolation_2 ] + // [ e0 ] + // Three content layers, three clip mask. + ASSERT_EQ(6u, RootLayer()->children().size()); ASSERT_EQ(3u, ContentLayerCount()); ASSERT_EQ(3u, SynthesizedClipLayerCount()); - const cc::Layer* dummy_c1 = RootLayer()->children()[0].get(); - const cc::Layer* content0 = RootLayer()->children()[1].get(); - const cc::Layer* clip_mask0 = RootLayer()->children()[2].get(); - const cc::Layer* dummy_e1 = RootLayer()->children()[3].get(); - const cc::Layer* content1 = RootLayer()->children()[4].get(); - const cc::Layer* clip_mask1 = RootLayer()->children()[5].get(); - const cc::Layer* content2 = RootLayer()->children()[6].get(); - const cc::Layer* clip_mask2 = RootLayer()->children()[7].get(); + const cc::Layer* content0 = RootLayer()->children()[0].get(); + const cc::Layer* clip_mask0 = RootLayer()->children()[1].get(); + const cc::Layer* content1 = RootLayer()->children()[2].get(); + const cc::Layer* clip_mask1 = RootLayer()->children()[3].get(); + const cc::Layer* content2 = RootLayer()->children()[4].get(); + const cc::Layer* clip_mask2 = RootLayer()->children()[5].get(); + constexpr int c0_id = 1; constexpr int e0_id = 1; - int c1_id = dummy_c1->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - ASSERT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - EXPECT_EQ(ContentLayerAt(0), content0); - EXPECT_EQ(c1_id, content0->clip_tree_index()); + int c1_id = content0->clip_tree_index(); + const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); + EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); + ASSERT_EQ(c0_id, cc_c1.parent_id); int mask_isolation_0_id = content0->effect_tree_index(); const cc::EffectNode& mask_isolation_0 = *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); @@ -2808,7 +2759,9 @@ ASSERT_EQ(mask_isolation_0_id, mask_effect_0.parent_id); EXPECT_EQ(SkBlendMode::kDstIn, mask_effect_0.blend_mode); - int e1_id = dummy_e1->effect_tree_index(); + EXPECT_EQ(ContentLayerAt(1), content1); + EXPECT_EQ(c1_id, content1->clip_tree_index()); + int e1_id = content1->effect_tree_index(); const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); EXPECT_EQ(SkBlendMode::kSrcOver, cc_e1.blend_mode); int mask_isolation_1_id = cc_e1.parent_id; @@ -2818,10 +2771,6 @@ ASSERT_EQ(e0_id, mask_isolation_1.parent_id); EXPECT_EQ(SkBlendMode::kMultiply, mask_isolation_1.blend_mode); - EXPECT_EQ(ContentLayerAt(1), content1); - EXPECT_EQ(c1_id, content1->clip_tree_index()); - EXPECT_EQ(e1_id, content1->effect_tree_index()); - EXPECT_EQ(SynthesizedClipLayerAt(1), clip_mask1); EXPECT_EQ(gfx::Size(300, 200), clip_mask1->bounds()); EXPECT_EQ(c1_id, clip_mask1->clip_tree_index());
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp index ec6d920..7a1159a 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
@@ -160,7 +160,6 @@ if (it != transform_node_map_.end()) return it->value; - scoped_refptr<cc::Layer> dummy_layer = cc::Layer::Create(); int parent_id = EnsureCompositorTransformNode(transform_node->Parent()); int id = GetTransformTree().Insert(cc::TransformNode(), parent_id); @@ -179,12 +178,6 @@ transform_node->FlattensInheritedTransform(); compositor_node.sorting_context_id = transform_node->RenderingContextId(); - root_layer_->AddChild(dummy_layer); - dummy_layer->SetTransformTreeIndex(id); - dummy_layer->SetClipTreeIndex(kSecondaryRootNodeId); - dummy_layer->SetEffectTreeIndex(kSecondaryRootNodeId); - dummy_layer->SetScrollTreeIndex(kRealRootNodeId); - dummy_layer->set_property_tree_sequence_number(sequence_number_); CompositorElementId compositor_element_id = transform_node->GetCompositorElementId(); if (compositor_element_id) { @@ -213,7 +206,6 @@ if (it != clip_node_map_.end()) return it->value; - scoped_refptr<cc::Layer> dummy_layer = cc::Layer::Create(); int parent_id = EnsureCompositorClipNode(clip_node->Parent()); int id = GetClipTree().Insert(cc::ClipNode(), parent_id); @@ -224,13 +216,6 @@ EnsureCompositorTransformNode(clip_node->LocalTransformSpace()); compositor_node.clip_type = cc::ClipNode::ClipType::APPLIES_LOCAL_CLIP; - root_layer_->AddChild(dummy_layer); - dummy_layer->SetTransformTreeIndex(compositor_node.transform_id); - dummy_layer->SetClipTreeIndex(id); - dummy_layer->SetEffectTreeIndex(kSecondaryRootNodeId); - dummy_layer->SetScrollTreeIndex(kRealRootNodeId); - dummy_layer->set_property_tree_sequence_number(sequence_number_); - auto result = clip_node_map_.Set(clip_node, id); DCHECK(result.is_new_entry); GetClipTree().set_needs_update(true); @@ -573,12 +558,6 @@ SkBlendMode used_blend_mode = SynthesizeCcEffectsForClipsIfNeeded( next_effect->OutputClip(), next_effect->BlendMode(), newly_built); - // We currently create dummy layers to host effect nodes and corresponding - // render surfaces. This should be removed once cc implements better support - // for freestanding property trees. - scoped_refptr<cc::Layer> dummy_layer = next_effect->EnsureDummyLayer(); - root_layer_->AddChild(dummy_layer); - int output_clip_id = EnsureCompositorClipNode(next_effect->OutputClip()); cc::EffectNode& effect_node = *GetEffectTree().Node( @@ -629,12 +608,6 @@ current_effect_ = next_effect; current_clip_ = next_effect->OutputClip(); - dummy_layer->set_property_tree_sequence_number(sequence_number_); - dummy_layer->SetTransformTreeIndex(kSecondaryRootNodeId); - dummy_layer->SetClipTreeIndex(output_clip_id); - dummy_layer->SetEffectTreeIndex(effect_node.id); - dummy_layer->SetScrollTreeIndex(kRealRootNodeId); - return true; }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h index 02ccc54..24de727 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h +++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h
@@ -138,9 +138,8 @@ cc::PropertyTrees& property_trees_; // The special layer which is the parent of every other layers. - // We currently add dummy layers as required by cc property nodes, but this - // may change in the future. We also generate clip mask layers for clips - // that can't be rendered by pure cc clip nodes. + // This is where clip mask layers we generated for synthesized clips are + // appended into. cc::Layer* root_layer_; // Maps from Blink-side property tree nodes to cc property node indices.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp index 7dc69931..40bd19d 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
@@ -26,13 +26,6 @@ return result; } -cc::Layer* EffectPaintPropertyNode::EnsureDummyLayer() const { - if (dummy_layer_) - return dummy_layer_.get(); - dummy_layer_ = cc::Layer::Create(); - return dummy_layer_.get(); -} - String EffectPaintPropertyNode::ToString() const { return String::Format( "parent=%p localTransformSpace=%p outputClip=%p opacity=%f filter=%s "
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h index d3c4001..07ceeba4 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h +++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
@@ -100,8 +100,6 @@ // |inputRect|. The rects are in the space of localTransformSpace. FloatRect MapRect(const FloatRect& input_rect) const; - cc::Layer* EnsureDummyLayer() const; - #if DCHECK_IS_ON() // The clone function is used by FindPropertiesNeedingUpdate.h for recording // an effect node before it has been updated, to later detect changes. @@ -185,13 +183,6 @@ SkBlendMode blend_mode_; // === End of effects === - // TODO(trchen): Remove the dummy layer. - // The main purpose of the dummy layer is to maintain a permanent identity - // to associate with cc::RenderSurfaceImpl for damage tracking. This shall - // be removed in favor of a stable ID once cc::LayerImpl no longer owns - // RenderSurfaceImpl. - mutable scoped_refptr<cc::Layer> dummy_layer_; - CompositingReasons direct_compositing_reasons_; CompositorElementId compositor_element_id_;
diff --git a/third_party/WebKit/public/platform/WebRuntimeFeatures.h b/third_party/WebKit/public/platform/WebRuntimeFeatures.h index 0d3f6e05..3fbb6a5a2 100644 --- a/third_party/WebKit/public/platform/WebRuntimeFeatures.h +++ b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
@@ -100,6 +100,7 @@ BLINK_PLATFORM_EXPORT static void EnableMojoBlobs(bool); BLINK_PLATFORM_EXPORT static void EnableNavigatorContentUtils(bool); BLINK_PLATFORM_EXPORT static void EnableNetInfoDownlinkMax(bool); + BLINK_PLATFORM_EXPORT static void EnableNetworkService(bool); BLINK_PLATFORM_EXPORT static void EnableNotificationConstructor(bool); BLINK_PLATFORM_EXPORT static void EnableNotificationContentImage(bool); BLINK_PLATFORM_EXPORT static void EnableNotifications(bool);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 206ff96..aa2061b 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -23435,6 +23435,7 @@ <int value="330138076" label="enable-clear-browsing-data-counters"/> <int value="332391072" label="cs-contextual-cards-bar-integration"/> <int value="334802038" label="OfflinePreviews:disabled"/> + <int value="339671131" label="disable-per-user-timezone"/> <int value="346711293" label="enable-save-password-bubble"/> <int value="348854923" label="v8-cache-strategies-for-cache-storage"/> <int value="352191859" label="disabled-new-style-notification"/>
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py index 1307515..c6d0fa6 100644 --- a/tools/perf/scripts_smoke_unittest.py +++ b/tools/perf/scripts_smoke_unittest.py
@@ -2,9 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import json import os import subprocess import sys +from telemetry.testing import options_for_unittests import unittest @@ -55,3 +57,28 @@ self.skipTest('small_profile_extender is missing') self.assertEquals(return_code, 0, stdout) self.assertIn('kraken', stdout) + + def testRunTelemetryBenchmarkAsGoogletest(self): + options = options_for_unittests.GetCopy() + browser_type = options.browser_type + return_code, stdout = self.RunPerfScript( + '../../testing/scripts/run_telemetry_benchmark_as_googletest.py ' + 'run_benchmark dummy_benchmark.stable_benchmark_1 --browser=%s ' + '--isolated-script-test-output=output.json ' + '--isolated-script-test-chartjson-output=chartjson_output.json ' + '--output-format=chartjson' % browser_type) + self.assertEquals(return_code, 0, stdout) + try: + with open('../../tools/perf/output.json') as f: + self.assertIsNotNone( + json.load(f), 'json_test_results should be populated: ' + stdout) + os.remove('../../tools/perf/output.json') + except IOError as e: + self.fail('json_test_results should be populated: ' + stdout + str(e)) + try: + with open('../../tools/perf/chartjson_output.json') as f: + self.assertIsNotNone( + json.load(f), 'chartjson should be populated: ' + stdout) + os.remove('../../tools/perf/chartjson_output.json') + except IOError as e: + self.fail('chartjson should be populated: ' + stdout + str(e))
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index fe79595..687b813 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -588,10 +588,9 @@ active_locks_.push_back(lock.get()); bool should_extend_timeout = false; - if ((scheduled_timeout_.is_null() || allow_locks_to_extend_timeout_) && - !timeout.is_zero()) { + if ((was_empty || allow_locks_to_extend_timeout_) && !timeout.is_zero()) { const base::TimeTicks time_to_timeout = base::TimeTicks::Now() + timeout; - // For the first lock, scheduled_timeout_.is_null is true, + // For the first lock, scheduled_timeout.is_null is true, // |time_to_timeout| will always larger than |scheduled_timeout_|. And it // is ok to invalidate the weakptr of |lock_timeout_weak_ptr_factory_|. if (time_to_timeout > scheduled_timeout_) {
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 6babbc1c..b01b4116 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -340,12 +340,9 @@ void RemoveAnimationObserver(CompositorAnimationObserver* observer); bool HasAnimationObserver(const CompositorAnimationObserver* observer) const; - // Creates a compositor lock. If the timeout is null, then no timeout is used. - // If multiple locks exist simultaneously, the timeout behavior is as follows: - // 1. if allow_locks_to_extend_timeouts has been set, all locks time out at - // the latest chronological timeout value provided; - // 2. otherwise, all locks time out at the time specified by the first lock - // that was created with a non-zero timeout value. + // Creates a compositor lock. Returns NULL if it is not possible to lock at + // this time (i.e. we're waiting to complete a previous unlock). If the + // timeout is null, then no timeout is used. std::unique_ptr<CompositorLock> GetCompositorLock( CompositorLockClient* client, base::TimeDelta timeout =
diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc index 4284504b..42491420 100644 --- a/ui/compositor/compositor_unittest.cc +++ b/ui/compositor/compositor_unittest.cc
@@ -451,38 +451,6 @@ compositor()->SetVisible(true); } -// Verify that when allow_locks_to_extend_timeout_ is false and a lock with -// no timeout has been created, a second lock that has a timeout will correctly -// time out. -TEST_F(CompositorTestWithMockedTime, - LockWithTimeoutOverridesLockWithNoTimeout) { - testing::StrictMock<MockCompositorLockClient> lock_client1; - std::unique_ptr<CompositorLock> lock1; - testing::StrictMock<MockCompositorLockClient> lock_client2; - std::unique_ptr<CompositorLock> lock2; - - base::TimeDelta timeout1 = base::TimeDelta(); - base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); - - // False is the default, but ensure this test is still valid if that ever - // changes. - compositor()->set_allow_locks_to_extend_timeout(false); - - // Take a lock with no timeout. - lock1 = compositor()->GetCompositorLock(&lock_client1, timeout1); - EXPECT_TRUE(compositor()->IsLocked()); - - // Setting a lock with a timeout should cause boths locks to time out. - lock2 = compositor()->GetCompositorLock(&lock_client2, timeout2); - EXPECT_TRUE(compositor()->IsLocked()); - - EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); - EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); - task_runner()->FastForwardBy(timeout2); - task_runner()->RunUntilIdle(); - EXPECT_FALSE(compositor()->IsLocked()); -} - #if defined(OS_WIN) // TODO(crbug.com/608436): Flaky on windows trybots #define MAYBE_CreateAndReleaseOutputSurface \
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc index c07e03e..315b1c0 100644 --- a/ui/ozone/platform/drm/gpu/drm_device.cc +++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -25,7 +25,6 @@ #include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" -#include "ui/ozone/public/ozone_switches.h" namespace ui { @@ -414,18 +413,15 @@ return false; } - if (use_atomic) { - if (!SetCapability(DRM_CLIENT_CAP_ATOMIC, 1)) { - LOG(ERROR) << "Drm atomic requested but capabilities don't allow it. To " - "switch to legacy page flip remove the command line flag " - << switches::kEnableDrmAtomic; - return false; - } + // Use atomic only if the build, kernel & flags all allow it. + if (use_atomic && SetCapability(DRM_CLIENT_CAP_ATOMIC, 1)) plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic()); - } else { - plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); - } + LOG_IF(WARNING, use_atomic && !plane_manager_) + << "Drm atomic requested but capabilities don't allow it. Falling back " + "to legacy page flip."; + if (!plane_manager_) + plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); if (!plane_manager_->Initialize(this)) { LOG(ERROR) << "Failed to initialize the plane manager for " << device_path_.value();