diff --git a/BUILD.gn b/BUILD.gn index d697f90..54d16ba 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -401,7 +401,6 @@ "//base:base_junit_tests", "//base/android/linker:chromium_android_linker", "//build/android/gyp/test:hello_world", - "//build/android/rezip", "//chrome/android/webapk/shell_apk:webapk", "//components/invalidation/impl:components_invalidation_impl_junit_tests", "//components/policy/android:components_policy_junit_tests",
diff --git a/DEPS b/DEPS index 923ce45..9076ffa 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '7a6c9f7be115031a8a86fdae20e8869fd973fdb6', + 'skia_revision': '2103cf0ff09763aeaa35508734f765aec9b75665', # 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': '783b1c5d041c3c612c5193a45937c060a32cc0d0', + 'v8_revision': '626575112bf0129d6cdf4ea5c843a2231a84fbbb', # 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. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '38c2705c697cd9a67b02ead1d601610d7af96524', + 'pdfium_revision': '6b71f22093fc4abb2da39f5a58b29c45c17ff99a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '201f910a0958c2c25481dc011616aada3df330d9', + 'catapult_revision': '143ba4ddeb05e6165fb8413c5f3f47d342922d24', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -228,7 +228,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'cda50c31ad6f31dfaa8568f6e23037dabb6b19e5', # commit position 16087 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ee5b9eaa30f9734c14c2d35130518b48da7eace6', # commit position 16098 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -273,7 +273,7 @@ Var('chromium_git') + '/external/github.com/google/cld_3.git' + '@' + 'ae02d6b8a2af41e87c956c7c7d3f651a8b7b9e79', 'src/third_party/libwebm/source': - Var('chromium_git') + '/webm/libwebm.git' + '@' + '9a235e0bc94319c5f7184bd69cbe5468a74a025c', + Var('chromium_git') + '/webm/libwebm.git' + '@' + '4956b2dec65352af32dc71bab553acb631c64177', 'src/third_party/pdfium': Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), @@ -397,7 +397,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': - Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '05cee9da77790110786e6211f75c49d0c7e26ae8', + Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'eb397c32a942a2839b2aa3638b6c0da5c3bee146', # Note that this is different from Android's freetype repo. 'src/third_party/freetype2/src':
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py index 74eac37..e3a766b 100755 --- a/android_webview/tools/apk_merger.py +++ b/android_webview/tools/apk_merger.py
@@ -135,8 +135,7 @@ def SignAndAlignApk(tmp_apk, signed_tmp_apk, new_apk, zipalign_path, - keystore_path, key_name, key_password, - page_align_shared_libraries): + keystore_path, key_name, key_password): try: finalize_apk.JarSigner( keystore_path, @@ -149,7 +148,6 @@ try: finalize_apk.AlignApk(zipalign_path, - page_align_shared_libraries, signed_tmp_apk, new_apk) except build_utils.CalledProcessError as e: @@ -179,8 +177,6 @@ expected_files = {'snapshot_blob_32.bin': False} if args.shared_library: expected_files[args.shared_library] = not args.uncompress_shared_libraries - if args.debug: - expected_files['gdbserver'] = True # need to unpack APKs to compare their contents UnpackApk(args.apk_64bit, tmp_dir_64) @@ -224,7 +220,8 @@ parser.add_argument('--key_name', required=True) parser.add_argument('--key_password', required=True) parser.add_argument('--shared_library') - parser.add_argument('--page-align-shared-libraries', action='store_true') + parser.add_argument('--page-align-shared-libraries', action='store_true', + help='Obsolete, but remains for backwards compatibility') parser.add_argument('--uncompress-shared-libraries', action='store_true') parser.add_argument('--debug', action='store_true') # This option shall only used in debug build, see http://crbug.com/631494. @@ -250,8 +247,7 @@ MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64) SignAndAlignApk(tmp_apk, signed_tmp_apk, new_apk, args.zipalign_path, - args.keystore_path, args.key_name, args.key_password, - args.page_align_shared_libraries) + args.keystore_path, args.key_name, args.key_password) except ApkMergeFailure as e: print e
diff --git a/ash/common/wm/overview/window_grid.cc b/ash/common/wm/overview/window_grid.cc index 6f013b3c..99a6e92 100644 --- a/ash/common/wm/overview/window_grid.cc +++ b/ash/common/wm/overview/window_grid.cc
@@ -313,7 +313,7 @@ widget_window->GetLayer()->GetAnimator()); animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetTweenType(gfx::Tween::EASE_IN_2); + animation_settings.SetTweenType(gfx::Tween::EASE_OUT); animation_settings.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); // CleanupAnimationObserver will delete itself (and the shield widget) when @@ -661,7 +661,7 @@ widget_window->GetLayer()->GetAnimator()); animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetTweenType(gfx::Tween::EASE_IN); + animation_settings.SetTweenType(gfx::Tween::EASE_OUT); animation_settings.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); shield_widget_->SetOpacity(kShieldOpacity);
diff --git a/base/metrics/persistent_memory_allocator.cc b/base/metrics/persistent_memory_allocator.cc index eecd19a..f32e9a3 100644 --- a/base/metrics/persistent_memory_allocator.cc +++ b/base/metrics/persistent_memory_allocator.cc
@@ -218,11 +218,9 @@ // again. Failing will also load the existing value into "last" so there // is no need to do another such load when the while-loop restarts. A // "strong" compare-exchange is used because failing unnecessarily would - // mean repeating some fairly costly validations above. This operation - // is "relaxed" because the iterator has no other values to protect and - // the referenced object will be accessed via an "acquire" in GetAsObject. + // mean repeating some fairly costly validations above. if (last_record_.compare_exchange_strong( - last, next, std::memory_order_relaxed, std::memory_order_relaxed)) { + last, next, std::memory_order_acq_rel, std::memory_order_acquire)) { *type_return = block->type_id.load(std::memory_order_relaxed); break; } @@ -638,6 +636,10 @@ return kReferenceNull; } + // Load information into the block header. There is no "release" of the + // data here because this memory can, currently, be seen only by the thread + // performing the allocation. When it comes time to share this, the thread + // will call MakeIterable() which does the release operation. block->size = size; block->cookie = kBlockCookieAllocated; block->type_id.store(type_id, std::memory_order_relaxed);
diff --git a/base/win/BUILD.gn b/base/win/BUILD.gn index ff2a754..74c1b8a 100644 --- a/base/win/BUILD.gn +++ b/base/win/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/buildflag_header.gni") +import("//build/config/sanitizers/sanitizers.gni") import("//build/win/message_compiler.gni") declare_args() { @@ -42,7 +43,9 @@ "eventlog_provider.cc", ] - ldflags = [ "/NOENTRY" ] + if (!is_asan) { + ldflags = [ "/NOENTRY" ] + } deps = [ "//base/win:eventlog_messages",
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py index 82ac496ed..6c20b05 100755 --- a/build/android/gyp/apkbuilder.py +++ b/build/android/gyp/apkbuilder.py
@@ -31,6 +31,9 @@ help='GYP-list of files to add as assets in the form ' '"srcPath:zipPath", where ":zipPath" is optional.', default='[]') + parser.add_argument('--java-resources', + help='GYP-list of java_resources JARs to include.', + default='[]') parser.add_argument('--write-asset-list', action='store_true', help='Whether to create an assets/assets_list file.') @@ -63,8 +66,6 @@ parser.add_argument('--native-lib-placeholders', help='GYP-list of native library placeholders to add.', default='[]') - parser.add_argument('--emma-device-jar', - help='Path to emma_device.jar to include.') parser.add_argument('--uncompress-shared-libraries', action='store_true', help='Uncompress shared libraries') @@ -74,6 +75,7 @@ options.uncompressed_assets) options.native_lib_placeholders = build_utils.ParseGnList( options.native_lib_placeholders) + options.java_resources = build_utils.ParseGnList(options.java_resources) all_libs = [] for gyp_list in options.native_libs: all_libs.extend(build_utils.ParseGnList(gyp_list)) @@ -161,14 +163,20 @@ def _AddNativeLibraries(out_apk, native_libs, android_abi, uncompress): """Add native libraries to APK.""" + has_crazy_linker = any('android_linker' in os.path.basename(p) + for p in native_libs) for path in native_libs: basename = os.path.basename(path) - apk_path = 'lib/%s/%s' % (android_abi, basename) compress = None - if (uncompress and os.path.splitext(basename)[1] == '.so'): + if (uncompress and os.path.splitext(basename)[1] == '.so' + and 'android_linker' not in basename): compress = False + # Add prefix to prevent android install from extracting upon install. + if has_crazy_linker: + basename = 'crazy.' + basename + apk_path = 'lib/%s/%s' % (android_abi, basename) build_utils.AddToZipHermetic(out_apk, apk_path, src_path=path, @@ -195,9 +203,6 @@ if options.dex_file: input_paths.append(options.dex_file) - if options.emma_device_jar: - input_paths.append(options.emma_device_jar) - input_strings = [options.android_abi, options.native_lib_placeholders, options.uncompress_shared_libraries] @@ -205,6 +210,9 @@ if options.secondary_android_abi: input_strings.append(options.secondary_android_abi) + if options.java_resources: + input_paths.extend(options.java_resources) + _assets = _ExpandPaths(options.assets) _uncompressed_assets = _ExpandPaths(options.uncompressed_assets) @@ -265,8 +273,9 @@ options.uncompress_shared_libraries) for name in sorted(options.native_lib_placeholders): - # Empty libs files are ignored by md5check, but rezip requires them - # to be empty in order to identify them as placeholders. + # Note: Empty libs files are ignored by md5check (can cause issues + # with stale builds when the only change is adding/removing + # placeholders). apk_path = 'lib/%s/%s' % (options.android_abi, name) build_utils.AddToZipHermetic(out_apk, apk_path, data='') @@ -274,24 +283,23 @@ for info in resource_infos[1:]: copy_resource(info) - # 6. Java resources. Used only when coverage is enabled, so order - # doesn't matter). - if options.emma_device_jar: - # Add EMMA Java resources to APK. - with zipfile.ZipFile(options.emma_device_jar, 'r') as emma_device_jar: - for apk_path in emma_device_jar.namelist(): + # 6. Java resources that should be accessible via + # Class.getResourceAsStream(), in particular parts of Emma jar. + # Prebuilt jars may contain class files which we shouldn't include. + for java_resource in options.java_resources: + with zipfile.ZipFile(java_resource, 'r') as java_resource_jar: + for apk_path in java_resource_jar.namelist(): apk_path_lower = apk_path.lower() + if apk_path_lower.startswith('meta-inf/'): continue - if apk_path_lower.endswith('/'): continue - if apk_path_lower.endswith('.class'): continue - build_utils.AddToZipHermetic(out_apk, apk_path, - data=emma_device_jar.read(apk_path)) + build_utils.AddToZipHermetic( + out_apk, apk_path, data=java_resource_jar.read(apk_path)) shutil.move(tmp_apk, options.output_apk) finally:
diff --git a/build/android/gyp/finalize_apk.py b/build/android/gyp/finalize_apk.py index 532d001f..ecb5ebfe 100755 --- a/build/android/gyp/finalize_apk.py +++ b/build/android/gyp/finalize_apk.py
@@ -21,32 +21,6 @@ from util import build_utils -def RenameInflateAndAddPageAlignment( - rezip_apk_jar_path, in_zip_file, out_zip_file): - rezip_apk_cmd = [ - 'java', - '-classpath', - rezip_apk_jar_path, - 'RezipApk', - 'renamealign', - in_zip_file, - out_zip_file, - ] - build_utils.CheckOutput(rezip_apk_cmd) - - -def ReorderAndAlignApk(rezip_apk_jar_path, in_zip_file, out_zip_file): - rezip_apk_cmd = [ - 'java', - '-classpath', - rezip_apk_jar_path, - 'RezipApk', - 'reorder', - in_zip_file, - out_zip_file, - ] - build_utils.CheckOutput(rezip_apk_cmd) - def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path): shutil.copy(unsigned_path, signed_path) @@ -62,14 +36,15 @@ build_utils.CheckOutput(sign_cmd) -def AlignApk(zipalign_path, package_align, unaligned_path, final_path): +def AlignApk(zipalign_path, unaligned_path, final_path): + # Note -p will page align native libraries (files ending with .so), but + # only those that are stored uncompressed. align_cmd = [ zipalign_path, - '-f' + '-p', + '-f', ] - if package_align: - align_cmd += ['-p'] align_cmd += [ '4', # 4 bytes @@ -85,23 +60,13 @@ parser = optparse.OptionParser() build_utils.AddDepfileOption(parser) - parser.add_option('--rezip-apk-jar-path', - help='Path to the RezipApk jar file.') parser.add_option('--zipalign-path', help='Path to the zipalign tool.') - parser.add_option('--page-align-shared-libraries', - action='store_true', - help='Page align shared libraries.') parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.') parser.add_option('--final-apk-path', help='Path to output signed and aligned APK.') parser.add_option('--key-path', help='Path to keystore for signing.') parser.add_option('--key-passwd', help='Keystore password') parser.add_option('--key-name', help='Keystore name') - parser.add_option('--stamp', help='Path to touch on success.') - parser.add_option('--load-library-from-zip', type='int', - help='If non-zero, build the APK such that the library can be loaded ' + - 'directly from the zip file using the crazy linker. The library ' + - 'will be renamed, uncompressed and page aligned.') options, _ = parser.parse_args() @@ -110,14 +75,9 @@ options.key_path, ] - if options.load_library_from_zip: - input_paths.append(options.rezip_apk_jar_path) - input_strings = [ - options.load_library_from_zip, options.key_name, options.key_passwd, - options.page_align_shared_libraries, ] build_utils.CallAndWriteDepfileIfStale( @@ -129,57 +89,34 @@ output_paths=[options.final_apk_path]) +def _NormalizeZip(path): + with tempfile.NamedTemporaryFile(suffix='.zip') as hermetic_signed_apk: + with zipfile.ZipFile(path, 'r') as zi: + with zipfile.ZipFile(hermetic_signed_apk, 'w') as zo: + for info in zi.infolist(): + # Ignore 'extended local file headers'. Python doesn't write them + # properly (see https://bugs.python.org/issue1742205) which causes + # zipalign to miscalculate alignment. Since we don't use them except + # for alignment anyway, we write a stripped file here and let + # zipalign add them properly later. eLFHs are controlled by 'general + # purpose bit flag 03' (0x08) so we mask that out. + info.flag_bits = info.flag_bits & 0xF7 + + info.date_time = build_utils.HERMETIC_TIMESTAMP + zo.writestr(info, zi.read(info.filename)) + + shutil.copy(hermetic_signed_apk.name, path) + + def FinalizeApk(options): - with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \ - tempfile.NamedTemporaryFile() as apk_to_sign_tmp: - - if options.load_library_from_zip: - # We alter the name of the library so that the Android Package Manager - # does not extract it into a separate file. This must be done before - # signing, as the filename is part of the signed manifest. At the same - # time we uncompress the library, which is necessary so that it can be - # loaded directly from the APK. - # Move the library to a page boundary by adding a page alignment file. - apk_to_sign = apk_to_sign_tmp.name - RenameInflateAndAddPageAlignment( - options.rezip_apk_jar_path, options.unsigned_apk_path, apk_to_sign) - else: - apk_to_sign = options.unsigned_apk_path - + with tempfile.NamedTemporaryFile() as signed_apk_path_tmp: signed_apk_path = signed_apk_path_tmp.name JarSigner(options.key_path, options.key_name, options.key_passwd, - apk_to_sign, signed_apk_path) + options.unsigned_apk_path, signed_apk_path) + # Make the newly added signing files hermetic. + _NormalizeZip(signed_apk_path) - # Make the signing files hermetic. - with tempfile.NamedTemporaryFile(suffix='.zip') as hermetic_signed_apk: - with zipfile.ZipFile(signed_apk_path, 'r') as zi: - with zipfile.ZipFile(hermetic_signed_apk, 'w') as zo: - for info in zi.infolist(): - # Ignore 'extended local file headers'. Python doesn't write them - # properly (see https://bugs.python.org/issue1742205) which causes - # zipalign to miscalculate alignment. Since we don't use them except - # for alignment anyway, we write a stripped file here and let - # zipalign add them properly later. eLFHs are controlled by 'general - # purpose bit flag 03' (0x08) so we mask that out. - info.flag_bits = info.flag_bits & 0xF7 - - info.date_time = build_utils.HERMETIC_TIMESTAMP - zo.writestr(info, zi.read(info.filename)) - - shutil.copy(hermetic_signed_apk.name, signed_apk_path) - - if options.load_library_from_zip: - # Reorder the contents of the APK. This re-establishes the canonical - # order which means the library will be back at its page aligned location. - # This step also aligns uncompressed items to 4 bytes. - ReorderAndAlignApk( - options.rezip_apk_jar_path, signed_apk_path, options.final_apk_path) - else: - # Align uncompressed items to 4 bytes - AlignApk(options.zipalign_path, - options.page_align_shared_libraries, - signed_apk_path, - options.final_apk_path) + AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path) if __name__ == '__main__':
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 6c29b89..3a529af 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -291,6 +291,10 @@ help='Whether this library should be treated as a prebuilt library by ' 'generate_gradle.py.') parser.add_option('--main-class', help='Java class for java_binary targets.') + parser.add_option('--java-resources-jar-path', + help='Path to JAR that contains java resources. Everything ' + 'from this JAR except meta-inf/ content and .class files ' + 'will be added to the final APK.') # android library options parser.add_option('--dex-path', help='Path to target\'s dex output.') @@ -677,6 +681,20 @@ config['uncompressed_locales_java_list'] = ( _CreateLocalePaksAssetJavaList(config['uncompressed_assets'])) + # Collect java resources + java_resources_jars = [d['java_resources_jar'] for d in all_library_deps + if 'java_resources_jar' in d] + if options.tested_apk_config: + tested_apk_resource_jars = [d['java_resources_jar'] + for d in tested_apk_library_deps + if 'java_resources_jar' in d] + java_resources_jars = [jar for jar in java_resources_jars + if jar not in tested_apk_resource_jars] + config['java_resources_jars'] = java_resources_jars + + if options.type == 'java_library' and options.java_resources_jar_path: + deps_info['java_resources_jar'] = options.java_resources_jar_path + build_utils.WriteJson(config, options.build_config, only_if_changed=True) if options.depfile:
diff --git a/build/android/rezip/BUILD.gn b/build/android/rezip/BUILD.gn deleted file mode 100644 index 1ace37c..0000000 --- a/build/android/rezip/BUILD.gn +++ /dev/null
@@ -1,10 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/config/android/rules.gni") - -java_library("rezip") { - jar_path = "$root_build_dir/lib.java/rezip_apk.jar" - java_files = [ "RezipApk.java" ] -}
diff --git a/build/android/rezip/RezipApk.java b/build/android/rezip/RezipApk.java deleted file mode 100644 index 43d75447..0000000 --- a/build/android/rezip/RezipApk.java +++ /dev/null
@@ -1,448 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.JarOutputStream; -import java.util.regex.Pattern; -import java.util.zip.CRC32; - -/** - * Command line tool used to build APKs which support loading the native code library - * directly from the APK file. To construct the APK we rename the native library by - * adding the prefix "crazy." to the filename. This is done to prevent the Android - * Package Manager from extracting the library. The native code must be page aligned - * and uncompressed. The page alignment is implemented by adding a zero filled file - * in front of the the native code library. This tool is designed so that running - * SignApk and/or zipalign on the resulting APK does not break the page alignment. - * This is achieved by outputing the filenames in the same canonical order used - * by SignApk and adding the same alignment fields added by zipalign. - */ -class RezipApk { - // Alignment to use for non-compressed files (must match zipalign). - private static final int ALIGNMENT = 4; - - // Alignment to use for non-compressed *.so files - private static final int LIBRARY_ALIGNMENT = 4096; - - // Files matching this pattern are not copied to the output when adding alignment. - // When reordering and verifying the APK they are copied to the end of the file. - private static Pattern sMetaFilePattern = - Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA)|com/android/otacert))|(" - + Pattern.quote(JarFile.MANIFEST_NAME) + ")$"); - - // Pattern for matching a shared library in the APK - private static Pattern sLibraryPattern = Pattern.compile("^lib/[^/]*/lib.*[.]so$"); - // Pattern for match the crazy linker in the APK - private static Pattern sCrazyLinkerPattern = - Pattern.compile("^lib/[^/]*/libchromium_android_linker.so$"); - // Pattern for matching a crazy loaded shared library in the APK - private static Pattern sCrazyLibraryPattern = Pattern.compile("^lib/[^/]*/crazy.lib.*[.]so$"); - - private static boolean isLibraryFilename(String filename) { - return sLibraryPattern.matcher(filename).matches() - && !sCrazyLinkerPattern.matcher(filename).matches(); - } - - private static boolean isCrazyLibraryFilename(String filename) { - return sCrazyLibraryPattern.matcher(filename).matches(); - } - - private static String renameLibraryForCrazyLinker(String filename) { - int lastSlash = filename.lastIndexOf('/'); - // We rename the library, so that the Android Package Manager - // no longer extracts the library. - return filename.substring(0, lastSlash + 1) + "crazy." + filename.substring(lastSlash + 1); - } - - /** - * Wraps another output stream, counting the number of bytes written. - */ - private static class CountingOutputStream extends OutputStream { - private long mCount = 0; - private OutputStream mOut; - - public CountingOutputStream(OutputStream out) { - this.mOut = out; - } - - /** Returns the number of bytes written. */ - public long getCount() { - return mCount; - } - - @Override public void write(byte[] b, int off, int len) throws IOException { - mOut.write(b, off, len); - mCount += len; - } - - @Override public void write(int b) throws IOException { - mOut.write(b); - mCount++; - } - - @Override public void close() throws IOException { - mOut.close(); - } - - @Override public void flush() throws IOException { - mOut.flush(); - } - } - - private static String outputName(JarEntry entry, boolean rename) { - String inName = entry.getName(); - if (rename && entry.getSize() > 0 && isLibraryFilename(inName)) { - return renameLibraryForCrazyLinker(inName); - } - return inName; - } - - /** - * Comparator used to sort jar entries from the input file. - * Sorting is done based on the output filename (which maybe renamed). - * Filenames are in natural string order, except that filenames matching - * the meta-file pattern are always after other files. This is so the manifest - * and signature are at the end of the file after any alignment file. - */ - private static class EntryComparator implements Comparator<JarEntry> { - private boolean mRename; - - public EntryComparator(boolean rename) { - mRename = rename; - } - - @Override - public int compare(JarEntry j1, JarEntry j2) { - String o1 = outputName(j1, mRename); - String o2 = outputName(j2, mRename); - boolean o1Matches = sMetaFilePattern.matcher(o1).matches(); - boolean o2Matches = sMetaFilePattern.matcher(o2).matches(); - if (o1Matches != o2Matches) { - return o1Matches ? 1 : -1; - } else { - return o1.compareTo(o2); - } - } - } - - // Build an ordered list of jar entries. The jar entries from the input are - // sorted based on the output filenames (which maybe renamed). If |omitMetaFiles| - // is true do not include the jar entries for the META-INF files. - // Entries are ordered in the deterministic order used by SignApk. - private static List<JarEntry> getOutputFileOrderEntries( - JarFile jar, boolean omitMetaFiles, boolean rename) { - List<JarEntry> entries = new ArrayList<JarEntry>(); - for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) { - JarEntry entry = e.nextElement(); - if (entry.isDirectory()) { - continue; - } - if (omitMetaFiles && sMetaFilePattern.matcher(entry.getName()).matches()) { - continue; - } - entries.add(entry); - } - - // We sort the input entries by name. When present META-INF files - // are sorted to the end. - Collections.sort(entries, new EntryComparator(rename)); - return entries; - } - - /** - * Add a zero filled alignment file at this point in the zip file, - * The added file will be added before |name| and after |prevName|. - * The size of the alignment file is such that the location of the - * file |name| will be on a LIBRARY_ALIGNMENT boundary. - * - * Note this arrangement is devised so that running SignApk and/or zipalign on the resulting - * file will not alter the alignment. - * - * @param offset number of bytes into the output file at this point. - * @param timestamp time in millis since the epoch to include in the header. - * @param name the name of the library filename. - * @param prevName the name of the previous file in the archive (or null). - * @param out jar output stream to write the alignment file to. - * - * @throws IOException if the output file can not be written. - */ - private static void addAlignmentFile( - long offset, long timestamp, String name, String prevName, - JarOutputStream out) throws IOException { - - // Compute the start and alignment of the library, as if it was next. - int headerSize = JarFile.LOCHDR + name.length(); - long libOffset = offset + headerSize; - int libNeeded = LIBRARY_ALIGNMENT - (int) (libOffset % LIBRARY_ALIGNMENT); - if (libNeeded == LIBRARY_ALIGNMENT) { - // Already aligned, no need to added alignment file. - return; - } - - // Check that there is not another file between the library and the - // alignment file. - String alignName = name.substring(0, name.length() - 2) + "align"; - if (prevName != null && prevName.compareTo(alignName) >= 0) { - throw new UnsupportedOperationException( - "Unable to insert alignment file, because there is " - + "another file in front of the file to be aligned. " - + "Other file: " + prevName + " Alignment file: " + alignName - + " file: " + name); - } - - // Compute the size of the alignment file header. - headerSize = JarFile.LOCHDR + alignName.length(); - // We are going to add an alignment file of type STORED. This file - // will itself induce a zipalign alignment adjustment. - int extraNeeded = - (ALIGNMENT - (int) ((offset + headerSize) % ALIGNMENT)) % ALIGNMENT; - headerSize += extraNeeded; - - if (libNeeded < headerSize + 1) { - // The header was bigger than the alignment that we need, add another page. - libNeeded += LIBRARY_ALIGNMENT; - } - // Compute the size of the alignment file. - libNeeded -= headerSize; - - // Build the header for the alignment file. - byte[] zeroBuffer = new byte[libNeeded]; - JarEntry alignEntry = new JarEntry(alignName); - alignEntry.setMethod(JarEntry.STORED); - alignEntry.setSize(libNeeded); - alignEntry.setTime(timestamp); - CRC32 crc = new CRC32(); - crc.update(zeroBuffer); - alignEntry.setCrc(crc.getValue()); - - if (extraNeeded != 0) { - alignEntry.setExtra(new byte[extraNeeded]); - } - - // Output the alignment file. - out.putNextEntry(alignEntry); - out.write(zeroBuffer); - out.closeEntry(); - out.flush(); - } - - // Make a JarEntry for the output file which corresponds to the input - // file. The output file will be called |name|. The output file will always - // be uncompressed (STORED). If the input is not STORED it is necessary to inflate - // it to compute the CRC and size of the output entry. - private static JarEntry makeStoredEntry(String name, JarEntry inEntry, JarFile in) - throws IOException { - JarEntry outEntry = new JarEntry(name); - outEntry.setMethod(JarEntry.STORED); - - if (inEntry.getMethod() == JarEntry.STORED) { - outEntry.setCrc(inEntry.getCrc()); - outEntry.setSize(inEntry.getSize()); - } else { - // We are inflating the file. We need to compute the CRC and size. - byte[] buffer = new byte[4096]; - CRC32 crc = new CRC32(); - int size = 0; - int num; - InputStream data = in.getInputStream(inEntry); - while ((num = data.read(buffer)) > 0) { - crc.update(buffer, 0, num); - size += num; - } - data.close(); - outEntry.setCrc(crc.getValue()); - outEntry.setSize(size); - } - return outEntry; - } - - /** - * Copy the contents of the input APK file to the output APK file. If |rename| is - * true then non-empty libraries (*.so) in the input will be renamed by prefixing - * "crazy.". This is done to prevent the Android Package Manager extracting the - * library. Note the crazy linker itself is not renamed, for bootstrapping reasons. - * Empty libraries are not renamed (they are in the APK to workaround a bug where - * the Android Package Manager fails to delete old versions when upgrading). - * There must be exactly one "crazy" library in the output stream. The "crazy" - * library will be uncompressed and page aligned in the output stream. Page - * alignment is implemented by adding a zero filled file, regular alignment is - * implemented by adding a zero filled extra field to the zip file header. If - * |addAlignment| is true a page alignment file is added, otherwise the "crazy" - * library must already be page aligned. Care is taken so that the output is generated - * in the same way as SignApk. This is important so that running SignApk and - * zipalign on the output does not break the page alignment. The archive may not - * contain a "*.apk" as SignApk has special nested signing logic that we do not - * support. - * - * @param in The input APK File. - * @param out The output APK stream. - * @param countOut Counting output stream (to measure the current offset). - * @param addAlignment Whether to add the alignment file or just check. - * @param rename Whether to rename libraries to be "crazy". - * - * @throws IOException if the output file can not be written. - */ - private static void rezip( - JarFile in, JarOutputStream out, CountingOutputStream countOut, - boolean addAlignment, boolean rename) throws IOException { - - List<JarEntry> entries = getOutputFileOrderEntries(in, addAlignment, rename); - long timestamp = System.currentTimeMillis(); - byte[] buffer = new byte[4096]; - boolean firstEntry = true; - String prevName = null; - int numCrazy = 0; - for (JarEntry inEntry : entries) { - // Rename files, if specied. - String name = outputName(inEntry, rename); - if (name.endsWith(".apk")) { - throw new UnsupportedOperationException( - "Nested APKs are not supported: " + name); - } - - // Build the header. - JarEntry outEntry = null; - boolean isCrazy = isCrazyLibraryFilename(name); - if (isCrazy) { - // "crazy" libraries are alway output uncompressed (STORED). - outEntry = makeStoredEntry(name, inEntry, in); - numCrazy++; - if (numCrazy > 1) { - throw new UnsupportedOperationException( - "Found more than one library\n" - + "Multiple libraries are not supported for APKs that use " - + "'load_library_from_zip'.\n" - + "See crbug/388223.\n" - + "Note, check that your build is clean.\n" - + "An unclean build can incorrectly incorporate old " - + "libraries in the APK."); - } - } else if (inEntry.getMethod() == JarEntry.STORED) { - // Preserve the STORED method of the input entry. - outEntry = new JarEntry(inEntry); - outEntry.setExtra(null); - } else { - // Create a new entry so that the compressed len is recomputed. - outEntry = new JarEntry(name); - } - outEntry.setTime(timestamp); - - // Compute and add alignment - long offset = countOut.getCount(); - if (firstEntry) { - // The first entry in a jar file has an extra field of - // four bytes that you can't get rid of; any extra - // data you specify in the JarEntry is appended to - // these forced four bytes. This is JAR_MAGIC in - // JarOutputStream; the bytes are 0xfeca0000. - firstEntry = false; - offset += 4; - } - if (outEntry.getMethod() == JarEntry.STORED) { - if (isCrazy) { - if (addAlignment) { - addAlignmentFile(offset, timestamp, name, prevName, out); - } - // We check that we did indeed get to a page boundary. - offset = countOut.getCount() + JarFile.LOCHDR + name.length(); - if ((offset % LIBRARY_ALIGNMENT) != 0) { - throw new AssertionError( - "Library was not page aligned when verifying page alignment. " - + "Library name: " + name + " Expected alignment: " - + LIBRARY_ALIGNMENT + "Offset: " + offset + " Error: " - + (offset % LIBRARY_ALIGNMENT)); - } - } else { - // This is equivalent to zipalign. - offset += JarFile.LOCHDR + name.length(); - int needed = (ALIGNMENT - (int) (offset % ALIGNMENT)) % ALIGNMENT; - if (needed != 0) { - outEntry.setExtra(new byte[needed]); - } - } - } - out.putNextEntry(outEntry); - - // Copy the data from the input to the output - int num; - InputStream data = in.getInputStream(inEntry); - while ((num = data.read(buffer)) > 0) { - out.write(buffer, 0, num); - } - data.close(); - out.closeEntry(); - out.flush(); - prevName = name; - } - if (numCrazy == 0) { - throw new AssertionError("There was no crazy library in the archive"); - } - } - - private static void usage() { - System.err.println("Usage: prealignapk (addalignment|reorder) input.apk output.apk"); - System.err.println("\"crazy\" libraries are always inflated in the output"); - System.err.println( - " renamealign - rename libraries with \"crazy.\" prefix and add alignment file"); - System.err.println(" align - add alignment file"); - System.err.println(" reorder - re-creates canonical ordering and checks alignment"); - System.exit(2); - } - - public static void main(String[] args) throws IOException { - if (args.length != 3) usage(); - - boolean addAlignment = false; - boolean rename = false; - if (args[0].equals("renamealign")) { - // Normal case. Before signing we rename the library and add an alignment file. - addAlignment = true; - rename = true; - } else if (args[0].equals("align")) { - // LGPL compliance case. Before signing, we add an alignment file to a - // reconstructed APK which already contains the "crazy" library. - addAlignment = true; - rename = false; - } else if (args[0].equals("reorder")) { - // Normal case. After jarsigning we write the file in the canonical order and check. - addAlignment = false; - } else { - usage(); - } - - String inputFilename = args[1]; - String outputFilename = args[2]; - - JarFile inputJar = null; - FileOutputStream outputFile = null; - - try { - inputJar = new JarFile(new File(inputFilename), true); - outputFile = new FileOutputStream(outputFilename); - - CountingOutputStream outCount = new CountingOutputStream(outputFile); - JarOutputStream outputJar = new JarOutputStream(outCount); - - // Match the compression level used by SignApk. - outputJar.setLevel(9); - - rezip(inputJar, outputJar, outCount, addAlignment, rename); - outputJar.close(); - } finally { - if (inputJar != null) inputJar.close(); - if (outputFile != null) outputFile.close(); - } - } -}
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index a662457..102e98c 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -32,7 +32,6 @@ # TODO(agrieve): Rename targets below to match above patterns. "*android_webview/glue:glue", - "//build/android/rezip:rezip", "//chrome/test/android/cast_emulator:cast_emulator", ] @@ -178,6 +177,12 @@ ] } + if (is_java && defined(invoker.java_resources_jar)) { + args += [ + "--java-resources-jar-path", + rebase_path(invoker.java_resources_jar, root_build_dir), + ] + } if (is_apk || is_deps_dex || (is_java && supports_android)) { args += [ "--dex-path", @@ -1339,6 +1344,10 @@ "--assets=@FileArg($_rebased_build_config:assets)", "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)", ] + + # TODO(mlopatkin) We are relying on the fact that assets_build_config is + # an APK build_config. + args += [ "--java-resources=@FileArg($_rebased_build_config:java_resources_jars)" ] } if (defined(invoker.write_asset_list) && invoker.write_asset_list) { args += [ "--write-asset-list" ] @@ -1380,12 +1389,6 @@ ] } - if (defined(invoker.emma_instrument) && invoker.emma_instrument) { - _emma_device_jar = "$android_sdk_root/tools/lib/emma_device.jar" - _rebased_emma_device_jar = rebase_path(_emma_device_jar, root_build_dir) - args += [ "--emma-device-jar=$_rebased_emma_device_jar" ] - } - if (defined(invoker.uncompress_shared_libraries) && invoker.uncompress_shared_libraries) { args += [ "--uncompress-shared-libraries" ] @@ -1401,7 +1404,6 @@ # keystore_path: Path to keystore to use for signing. # keystore_name: Key alias to use. # keystore_password: Keystore password. - # rezip_apk: Whether to add crazy-linker alignment. template("finalize_apk") { action(target_name) { deps = [] @@ -1444,20 +1446,6 @@ "--key-passwd", invoker.keystore_password, ] - if (defined(invoker.rezip_apk) && invoker.rezip_apk) { - deps += [ "//build/android/rezip" ] - _rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar" - args += [ - "--load-library-from-zip=1", - "--rezip-apk-jar-path", - rebase_path(_rezip_jar_path, root_build_dir), - ] - } - - if (defined(invoker.page_align_shared_libraries) && - invoker.page_align_shared_libraries) { - args += [ "--page-align-shared-libraries" ] - } } } @@ -1697,7 +1685,6 @@ forward_variables_from(invoker, [ "assets_build_config", - "emma_instrument", "native_lib_placeholders", "native_libs_filearg", "secondary_abi_native_libs_filearg", @@ -1705,6 +1692,9 @@ "uncompress_shared_libraries", "write_asset_list", ]) + if (!defined(uncompress_shared_libraries)) { + uncompress_shared_libraries = _load_library_from_apk + } deps = _deps + [ ":${_package_resources_target_name}" ] native_libs = _native_libs + _native_libs_even_when_incremental @@ -1721,10 +1711,12 @@ forward_variables_from(invoker, [ "assets_build_config", - "emma_instrument", "secondary_native_libs", "uncompress_shared_libraries", ]) + if (!defined(uncompress_shared_libraries)) { + uncompress_shared_libraries = _load_library_from_apk + } _dex_target = "//build/android/incremental_install:bootstrap_java__dex" deps = _incremental_deps + [ ":${_incremental_package_resources_target_name}", @@ -1751,14 +1743,11 @@ _finalize_apk_rule_name = "${target_name}__finalize" finalize_apk(_finalize_apk_rule_name) { - forward_variables_from(invoker, [ "page_align_shared_libraries" ]) - input_apk_path = _packaged_apk_path output_apk_path = _final_apk_path keystore_path = _keystore_path keystore_name = _keystore_name keystore_password = _keystore_password - rezip_apk = _load_library_from_apk public_deps = [ # Generator of the _packaged_apk_path this target takes as input. @@ -1887,6 +1876,12 @@ if (_supports_android) { dex_path = _dex_path } + if (defined(invoker.include_java_resources) && + invoker.include_java_resources) { + # Use original jar_path because _jar_path points to a library without + # resources. + java_resources_jar = invoker.jar_path + } } process_java_prebuilt(_process_jar_target_name) {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 43279e8..1db01006 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -2018,15 +2018,7 @@ _extra_native_libs_deps = [] assert(_extra_native_libs_deps == []) # Mark as used. _extra_native_libs_even_when_incremental = [] - _extra_native_libs_even_when_incremental_deps = [] - assert(_extra_native_libs_even_when_incremental_deps == []) # Mark as used. if (_native_libs_deps != []) { - # zipalign can't align gdb_server, don't pack gdbserver temporarily. - if (is_debug && (!defined(invoker.page_align_shared_libraries) || - !invoker.page_align_shared_libraries)) { - _extra_native_libs_even_when_incremental = [ android_gdbserver ] - } - if (_use_chromium_linker) { _extra_native_libs = [ "$root_shlib_dir/libchromium_android_linker$shlib_extension" ] @@ -2049,7 +2041,6 @@ "deps", "extensions_to_not_compress", "language_splits", - "page_align_shared_libraries", "public_deps", "secondary_native_libs", "shared_resources", @@ -2066,7 +2057,6 @@ dex_path = final_dex_path load_library_from_apk = _load_library_from_apk create_density_splits = _create_density_splits - emma_instrument = emma_coverage && !_emma_never_instrument if (!defined(extensions_to_not_compress)) { # Allow icu data, v8 snapshots, and pak files to be loaded directly from @@ -2099,7 +2089,6 @@ _extra_native_libs_even_when_incremental != []) && !_create_abi_split) { deps += _native_libs_deps + _extra_native_libs_deps + - _extra_native_libs_even_when_incremental_deps + [ _native_libs_file_arg_dep ] native_libs_filearg = _native_libs_file_arg native_libs = _extra_native_libs @@ -2160,9 +2149,7 @@ "public_deps", ]) - incremental_deps = - deps + _extra_native_libs_even_when_incremental_deps + - [ ":$_manifest_rule" ] + incremental_deps = deps + [ ":$_manifest_rule" ] deps = [] deps = incremental_deps + _native_libs_deps + _extra_native_libs_deps + [ _native_libs_file_arg_dep ]
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn index ce631b6c..a28fad5d 100644 --- a/build/secondary/third_party/android_tools/BUILD.gn +++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -39,6 +39,7 @@ android_java_prebuilt("emma_device_java") { jar_path = "$android_sdk_root/tools/lib/emma_device.jar" + include_java_resources = true } android_aar_prebuilt("android_support_design_java") {
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index 434e0b9e..8605c86 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -156,7 +156,7 @@ } int RenderSurfaceImpl::ClipTreeIndex() const { - return owning_layer_->clip_tree_index(); + return OwningEffectNode()->clip_id; } int RenderSurfaceImpl::EffectTreeIndex() const { @@ -349,12 +349,12 @@ } int RenderSurfaceImpl::GetRenderPassId() { - return owning_layer_->id(); + return id(); } void RenderSurfaceImpl::AppendRenderPasses(RenderPassSink* pass_sink) { std::unique_ptr<RenderPass> pass = RenderPass::Create(layer_list_.size()); - pass->SetNew(owning_layer_->id(), content_rect(), + pass->SetNew(id(), content_rect(), gfx::IntersectRects(content_rect(), damage_tracker_->current_damage_rect()), draw_properties_.screen_space_transform);
diff --git a/cc/trees/clip_node.cc b/cc/trees/clip_node.cc index c7f85bf..f643013 100644 --- a/cc/trees/clip_node.cc +++ b/cc/trees/clip_node.cc
@@ -5,6 +5,7 @@ #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event_argument.h" #include "cc/base/math_util.h" +#include "cc/layers/layer.h" #include "cc/proto/cc_conversions.h" #include "cc/proto/gfx_conversions.h" #include "cc/trees/clip_node.h" @@ -13,13 +14,13 @@ namespace cc { ClipNode::ClipNode() - : id(-1), - parent_id(-1), - owning_layer_id(-1), + : id(ClipTree::kInvalidNodeId), + parent_id(ClipTree::kInvalidNodeId), + owning_layer_id(Layer::INVALID_ID), clip_type(ClipType::NONE), - transform_id(-1), - target_transform_id(-1), - target_effect_id(-1), + transform_id(TransformTree::kInvalidNodeId), + target_transform_id(TransformTree::kInvalidNodeId), + target_effect_id(EffectTree::kInvalidNodeId), layer_clipping_uses_only_local_clip(false), layers_are_clipped(false), layers_are_clipped_when_surfaces_disabled(false),
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index 84b3e8f..9251bef 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -1457,8 +1457,7 @@ const ClipNode* clip_node = property_trees->clip_tree.Node(render_surface->ClipTreeIndex()); - SetSurfaceClipRect(property_trees->clip_tree.parent(clip_node), - property_trees, render_surface); + SetSurfaceClipRect(clip_node, property_trees, render_surface); } #if DCHECK_IS_ON()
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc index fa5ce228..e284ac6e 100644 --- a/cc/trees/effect_node.cc +++ b/cc/trees/effect_node.cc
@@ -3,16 +3,18 @@ // found in the LICENSE file. #include "base/trace_event/trace_event_argument.h" +#include "cc/layers/layer.h" #include "cc/proto/gfx_conversions.h" #include "cc/proto/skia_conversions.h" #include "cc/trees/effect_node.h" +#include "cc/trees/property_tree.h" namespace cc { EffectNode::EffectNode() - : id(-1), - parent_id(-1), - owning_layer_id(-1), + : id(EffectTree::kInvalidNodeId), + parent_id(EffectTree::kInvalidNodeId), + owning_layer_id(Layer::INVALID_ID), opacity(1.f), screen_space_opacity(1.f), blend_mode(SkBlendMode::kSrcOver),
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index d589a3a9..97dc00ea 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -10656,7 +10656,6 @@ parent2, nullptr); ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root1.get()); - const int kInvalidPropertyTreeNodeId = -1; const int kRootPropertyTreeNodeId = 0; // Property tree root @@ -10667,8 +10666,8 @@ ScrollTree& expected_scroll_tree = property_trees.scroll_tree; ScrollNode* property_tree_root = expected_scroll_tree.Node(0); property_tree_root->id = kRootPropertyTreeNodeId; - property_tree_root->parent_id = kInvalidPropertyTreeNodeId; - property_tree_root->owning_layer_id = kInvalidPropertyTreeNodeId; + property_tree_root->parent_id = ScrollTree::kInvalidNodeId; + property_tree_root->owning_layer_id = Layer::INVALID_ID; property_tree_root->scrollable = false; property_tree_root->main_thread_scrolling_reasons = MainThreadScrollingReason::kNotScrollingOnMain;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 8602c5d..edf102ef 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -585,7 +585,7 @@ device_viewport_point, type, layer_impl, &scroll_on_main_thread, &main_thread_scrolling_reasons); - if (!test_layer_impl) + if (scroll_on_main_thread) return false; if (scrolling_layer_impl == test_layer_impl) @@ -1664,7 +1664,6 @@ } } - CompositorFrame compositor_frame; compositor_frame.metadata = std::move(metadata); resource_provider_->PrepareSendToParent(resources, @@ -2534,7 +2533,7 @@ // Walk up the hierarchy and look for a scrollable layer. ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree; - LayerImpl* potentially_scrolling_layer_impl = NULL; + LayerImpl* potentially_scrolling_layer_impl = nullptr; if (layer_impl) { ScrollNode* scroll_node = scroll_tree.Node(layer_impl->scroll_tree_index()); for (; scroll_tree.parent(scroll_node); @@ -2546,7 +2545,7 @@ if (IsMainThreadScrolling(status, scroll_node)) { *scroll_on_main_thread = true; *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons; - return NULL; + return active_tree_->LayerById(scroll_node->owning_layer_id); } if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD && @@ -2575,7 +2574,6 @@ if (IsMainThreadScrolling(status, scroll_node)) { *scroll_on_main_thread = true; *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons; - return NULL; } } @@ -2687,15 +2685,15 @@ device_viewport_point, type, layer_impl, &scroll_on_main_thread, &scroll_status.main_thread_scrolling_reasons); } - if (scrolling_layer_impl) - scroll_affects_scroll_handler_ = - scrolling_layer_impl->layer_tree_impl()->have_scroll_event_handlers(); if (scroll_on_main_thread) { RecordCompositorSlowScrollMetric(type, MAIN_THREAD); scroll_status.thread = SCROLL_ON_MAIN_THREAD; return scroll_status; + } else if (scrolling_layer_impl) { + scroll_affects_scroll_handler_ = + scrolling_layer_impl->layer_tree_impl()->have_scroll_event_handlers(); } return ScrollBeginImpl(scroll_state, scrolling_layer_impl, type); @@ -3251,7 +3249,7 @@ // Check if mouse is over a scrollbar or not. // TODO(sahel): get rid of this extera checking when // FindScrollLayerForDeviceViewportPoint finds the proper layer for - // scrolling on main thread, as well. + // scrolling on main thread when mouse is over scrollbar as well. int new_id = Layer::INVALID_ID; if (layer_impl && layer_impl->ToScrollbarLayer()) new_id = layer_impl->ToScrollbarLayer()->ScrollLayerId();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 3f839f8..79f9496 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -463,6 +463,8 @@ void SetupMouseMoveAtWithDeviceScale(float device_scale_factor); + void SetupMouseMoveAtTestScrollbarStates(bool main_thread_scrolling); + scoped_refptr<AnimationTimeline> timeline() { return timeline_; } protected: @@ -11600,7 +11602,8 @@ EXPECT_FALSE(host_impl_->use_gpu_rasterization()); } -TEST_F(LayerTreeHostImplTest, LayerTreeHostImplTestScrollbarStates) { +void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates( + bool main_thread_scrolling) { LayerTreeSettings settings = DefaultSettings(); settings.scrollbar_fade_delay = base::TimeDelta::FromMilliseconds(500); settings.scrollbar_fade_duration = base::TimeDelta::FromMilliseconds(300); @@ -11626,6 +11629,11 @@ LayerImpl* root_scroll = host_impl_->active_tree()->OuterViewportScrollLayer(); + if (main_thread_scrolling) { + root_scroll->set_main_thread_scrolling_reasons( + MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects); + } + // scrollbar_1 on root scroll. std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar_1 = SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), @@ -11684,6 +11692,11 @@ child->SetDrawsContent(true); child->SetScrollClipLayer(child_clip_id); + if (main_thread_scrolling) { + child->set_main_thread_scrolling_reasons( + MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects); + } + scrollbar_2->SetScrollLayerId(child_scroll_id); scrollbar_2->SetDrawsContent(true); scrollbar_2->SetBounds(scrollbar_size_2); @@ -11725,5 +11738,15 @@ EXPECT_FALSE(scrollbar_2_animation_controller->mouse_is_over_scrollbar()); } +TEST_F(LayerTreeHostImplTest, + LayerTreeHostImplTestScrollbarStatesInMainThreadScorlling) { + SetupMouseMoveAtTestScrollbarStates(true); +} + +TEST_F(LayerTreeHostImplTest, + LayerTreeHostImplTestScrollbarStatesInNotMainThreadScorlling) { + SetupMouseMoveAtTestScrollbarStates(false); +} + } // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 0344d8f..e041ce32 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -156,7 +156,7 @@ DidUpdateScrollState(layer_id); TransformTree& transform_tree = property_trees()->transform_tree; ScrollTree& scroll_tree = property_trees()->scroll_tree; - int transform_id = -1; + int transform_id = TransformTree::kInvalidNodeId; // If pending tree topology changed and we still want to notify the pending // tree about scroll offset in the active tree, we may not find the @@ -171,7 +171,7 @@ return; } - if (transform_id != -1) { + if (transform_id != TransformTree::kInvalidNodeId) { TransformNode* node = transform_tree.Node(transform_id); if (node->scroll_offset != scroll_tree.current_scroll_offset(layer_id)) { node->scroll_offset = scroll_tree.current_scroll_offset(layer_id); @@ -617,7 +617,8 @@ ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode(); int old_id = scroll_node ? scroll_node->owning_layer_id : Layer::INVALID_ID; int new_id = layer ? layer->id() : Layer::INVALID_ID; - int new_scroll_node_id = layer ? layer->scroll_tree_index() : -1; + int new_scroll_node_id = + layer ? layer->scroll_tree_index() : ScrollTree::kInvalidNodeId; if (layer) last_scrolled_layer_id_ = new_id;
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index e56c0e42..1bef82ef 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -923,7 +923,7 @@ // the surface to the space of the surface itself. int destination_id = effect_node->transform_id; int source_id; - if (effect_node->parent_id != -1) { + if (effect_node->parent_id != EffectTree::kInvalidNodeId) { // For non-root surfaces, transform only by sub-layer scale. source_id = destination_id; } else { @@ -968,7 +968,7 @@ if (node->has_copy_request) return node->id; else - return -1; + return EffectTree::kInvalidNodeId; } void EffectTree::AddMaskLayerId(int id) { @@ -1981,9 +1981,10 @@ int dest_id) const { for (auto& transform_data : cached_data_.draw_transforms[transform_id]) { // We initialize draw_transforms with 1 element vectors when - // ResetCachedData, so if we hit a -1 target id, it means it's the first - // time we compute draw transforms after reset. - if (transform_data.target_id == dest_id || transform_data.target_id == -1) { + // ResetCachedData, so if we hit an invalid target id, it means it's the + // first time we compute draw transforms after reset. + if (transform_data.target_id == dest_id || + transform_data.target_id == EffectTree::kInvalidNodeId) { return transform_data; } }
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index e2c12539..d68bb307 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -533,7 +533,7 @@ // performance. DrawTransformData() : update_number(-1), - target_id(-1), + target_id(EffectTree::kInvalidNodeId), transforms(gfx::Transform(), gfx::Transform()) {} };
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index 1e6cb286..bcf5615b 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -30,7 +30,6 @@ namespace { -static const int kInvalidPropertyTreeNodeId = -1; static const int kRootPropertyTreeNodeId = 0; static const int kViewportClipTreeNodeId = 1; @@ -670,7 +669,7 @@ ->transform_id); DCHECK_NE( data_for_children->property_trees->transform_tree.TargetId(node->id), - kInvalidPropertyTreeNodeId); + TransformTree::kInvalidNodeId); node->has_potential_animation = has_potentially_animated_transform; node->is_currently_animating = TransformIsAnimating(layer); @@ -1173,7 +1172,7 @@ if (layer->scroll_clip_layer()) { clip_bounds = layer->scroll_clip_layer()->bounds(); DCHECK(layer->scroll_clip_layer()->transform_tree_index() != - kInvalidPropertyTreeNodeId); + TransformTree::kInvalidNodeId); node.max_scroll_offset_affected_by_page_scale = !data_from_ancestor.property_trees->transform_tree .Node(layer->scroll_clip_layer()->transform_tree_index()) @@ -1427,7 +1426,7 @@ data_for_recursion.transform_fixed_parent = nullptr; data_for_recursion.render_target = kRootPropertyTreeNodeId; data_for_recursion.clip_tree_parent = kRootPropertyTreeNodeId; - data_for_recursion.effect_tree_parent = kInvalidPropertyTreeNodeId; + data_for_recursion.effect_tree_parent = EffectTree::kInvalidNodeId; data_for_recursion.scroll_tree_parent = kRootPropertyTreeNodeId; data_for_recursion.page_scale_layer = page_scale_layer; data_for_recursion.inner_viewport_scroll_layer = inner_viewport_scroll_layer;
diff --git a/cc/trees/scroll_node.cc b/cc/trees/scroll_node.cc index 0e0c7777..7b46d12b 100644 --- a/cc/trees/scroll_node.cc +++ b/cc/trees/scroll_node.cc
@@ -5,16 +5,18 @@ #include "base/trace_event/trace_event_argument.h" #include "cc/base/math_util.h" #include "cc/input/main_thread_scrolling_reason.h" +#include "cc/layers/layer.h" #include "cc/proto/gfx_conversions.h" #include "cc/trees/element_id.h" +#include "cc/trees/property_tree.h" #include "cc/trees/scroll_node.h" namespace cc { ScrollNode::ScrollNode() - : id(-1), - parent_id(-1), - owning_layer_id(-1), + : id(ScrollTree::kInvalidNodeId), + parent_id(ScrollTree::kInvalidNodeId), + owning_layer_id(Layer::INVALID_ID), scrollable(false), main_thread_scrolling_reasons( MainThreadScrollingReason::kNotScrollingOnMain),
diff --git a/cc/trees/transform_node.cc b/cc/trees/transform_node.cc index 97b5cf9f..83d25ec 100644 --- a/cc/trees/transform_node.cc +++ b/cc/trees/transform_node.cc
@@ -4,18 +4,20 @@ #include "base/trace_event/trace_event_argument.h" #include "cc/base/math_util.h" +#include "cc/layers/layer.h" #include "cc/proto/gfx_conversions.h" +#include "cc/trees/property_tree.h" #include "cc/trees/transform_node.h" #include "ui/gfx/geometry/point3_f.h" namespace cc { TransformNode::TransformNode() - : id(-1), - parent_id(-1), - owning_layer_id(-1), + : id(TransformTree::kInvalidNodeId), + parent_id(TransformTree::kInvalidNodeId), + owning_layer_id(Layer::INVALID_ID), sticky_position_constraint_id(-1), - source_node_id(-1), + source_node_id(TransformTree::kInvalidNodeId), sorting_context_id(0), needs_local_transform_update(true), node_and_ancestors_are_animated_or_invertible(true),
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index 7dafeeb2..01d5f66a 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -111,7 +111,6 @@ # Configrations to make android load shared library from APK. uncompress_shared_libraries = true - page_align_shared_libraries = true forward_variables_from(invoker, "*")
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java index a04a76d1..d0ec482 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -678,10 +678,9 @@ return nativeSetCreditCard(mPersonalDataManagerAndroid, card); } - public void updateServerCardBillingAddress(String cardServerId, String billingAddressId) { + public void updateServerCardBillingAddress(CreditCard card) { ThreadUtils.assertOnUiThread(); - nativeUpdateServerCardBillingAddress( - mPersonalDataManagerAndroid, cardServerId, billingAddressId); + nativeUpdateServerCardBillingAddress(mPersonalDataManagerAndroid, card); } public String getBasicCardPaymentType(String cardNumber, boolean emptyIfInvalid) { @@ -908,7 +907,7 @@ private native String nativeSetCreditCard(long nativePersonalDataManagerAndroid, CreditCard card); private native void nativeUpdateServerCardBillingAddress(long nativePersonalDataManagerAndroid, - String guid, String billingAddressId); + CreditCard card); private native String nativeGetBasicCardPaymentType( long nativePersonalDataManagerAndroid, String cardNumber, boolean emptyIfInvalid); private native void nativeAddServerCreditCardForTest(long nativePersonalDataManagerAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardsVariationParameters.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardsVariationParameters.java index f2da715..0681a57 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardsVariationParameters.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardsVariationParameters.java
@@ -7,12 +7,18 @@ import android.text.TextUtils; import org.chromium.base.Log; +import org.chromium.base.VisibleForTesting; import org.chromium.components.variations.VariationsAssociatedData; +import java.util.Map; + /** * Provides easy access to data for field trials to do with the Cards UI. */ public final class CardsVariationParameters { + /** Map that stores substitution values for params. */ + private static Map<String, String> sTestVariationParams; + // Tags are limited to 20 characters. private static final String TAG = "CardsVariationParams"; @@ -24,6 +30,8 @@ private static final String PARAM_FIRST_CARD_ANIMATION_MAX_RUNS = "first_card_animation_max_runs"; private static final String PARAM_SCROLL_BELOW_THE_FOLD = "scroll_below_the_fold"; + private static final String PARAM_IGNORE_UPDATES_FOR_EXISTING_SUGGESTIONS = + "ignore_updates_for_existing_suggestions"; private static final String PARAM_DISABLED_VALUE = "off"; @@ -31,6 +39,16 @@ private CardsVariationParameters() {} + // TODO(jkrcal): Do a proper general fix in VariationsAssociatedData in the spirit of + // @EnableFeatures and ChromeFeatureList. + /** + * Sets the parameter values to use in JUnit tests, since native calls are not available there. + */ + @VisibleForTesting + public static void setTestVariationParams(Map<String, String> variationParams) { + sTestVariationParams = variationParams; + } + /** * Provides the value of the field trial to offset the peeking card (can be overridden * with a command line flag). It will return 0 if there is no such field trial. @@ -50,19 +68,23 @@ * @return Whether the NTP should initially be scrolled below the fold. */ public static boolean isScrollBelowTheFoldEnabled() { - return Boolean.parseBoolean(VariationsAssociatedData.getVariationParamValue( - FIELD_TRIAL_NAME, PARAM_SCROLL_BELOW_THE_FOLD)); + return Boolean.parseBoolean(getParamValue(PARAM_SCROLL_BELOW_THE_FOLD)); + } + + /** + * @return Whether the NTP should ignore updates for suggestions that have not been seen yet. + */ + public static boolean ignoreUpdatesForExistingSuggestions() { + return Boolean.parseBoolean(getParamValue(PARAM_IGNORE_UPDATES_FOR_EXISTING_SUGGESTIONS)); } public static boolean isFaviconServiceEnabled() { - return !PARAM_DISABLED_VALUE.equals(VariationsAssociatedData.getVariationParamValue( - FIELD_TRIAL_NAME, PARAM_FAVICON_SERVICE_NAME)); + return !PARAM_DISABLED_VALUE.equals(getParamValue(PARAM_FAVICON_SERVICE_NAME)); } private static int getIntValue(String paramName, int defaultValue) { // TODO(jkrcal): Get parameter by feature name, not field trial name. - String value = VariationsAssociatedData.getVariationParamValue( - FIELD_TRIAL_NAME, paramName); + String value = getParamValue(paramName); if (!TextUtils.isEmpty(value)) { try { @@ -74,4 +96,14 @@ return defaultValue; } + + private static String getParamValue(String paramName) { + if (sTestVariationParams != null) { + String value = sTestVariationParams.get(paramName); + if (value == null) return ""; + return value; + } + + return VariationsAssociatedData.getVariationParamValue(FIELD_TRIAL_NAME, paramName); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java index 5057a76e..3d710bb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -610,6 +610,7 @@ * To be triggered when a snippet is bound to a ViewHolder. */ public void onSnippetBound(View cardView) { + // Animate the peeking card. // We only run if the feature is enabled and once per NTP. if (!SnippetsConfig.isIncreasedCardVisibilityEnabled() || mFirstCardAnimationRun) return; mFirstCardAnimationRun = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java index a0190f41..c4ecfd88 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -97,8 +97,8 @@ addChild(section); } - // Add the new suggestions. - setSuggestions(category, suggestions, categoryStatus); + // Set the new suggestions. + setSuggestions(category, suggestions, categoryStatus, /* replaceExisting = */ true); return suggestions.size(); } @@ -110,9 +110,6 @@ if (!canLoadSuggestions(category, status)) return; - // We never want to refresh the suggestions if we already have some content. - if (mSections.get(category).hasSuggestions()) return; - List<SnippetArticle> suggestions = mNewTabPageManager.getSuggestionsSource().getSuggestionsForCategory(category); @@ -121,7 +118,7 @@ // At first, there might be no suggestions available, we wait until they have been fetched. if (suggestions.isEmpty()) return; - setSuggestions(category, suggestions, status); + setSuggestions(category, suggestions, status, /* replaceExisting = */ true); } @Override @@ -130,7 +127,7 @@ int status = mNewTabPageManager.getSuggestionsSource().getCategoryStatus(category); if (!canLoadSuggestions(category, status)) return; - setSuggestions(category, suggestions, status); + setSuggestions(category, suggestions, status, /* replaceExisting = */ false); } @Override @@ -173,8 +170,19 @@ resetSections(/* alwaysAllowEmptySections = */false); } + /** + * Puts {@code suggestions} into given {@code category}. It can either replace all existing + * suggestions with the new ones or append the new suggestions at the end of the list. This call + * may have no or only partial effect if changing the list of suggestions is not allowed (e.g. + * because the user has already seen the suggestions). + * @param category The category for which the suggestions should be set. + * @param suggestions The new list of suggestions for the given category. + * @param status The new category status. + * @param replaceExisting If true, {@code suggestions} replace the current list of suggestions. + * If false, {@code suggestions} are appended to current list of suggestions. + */ private void setSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions, - @CategoryStatusEnum int status) { + @CategoryStatusEnum int status, boolean replaceExisting) { // Count the number of suggestions before this category. int globalPositionOffset = 0; for (Map.Entry<Integer, SuggestionsSection> entry : mSections.entrySet()) { @@ -186,7 +194,7 @@ suggestion.mGlobalPosition = globalPositionOffset + suggestion.mPosition; } - mSections.get(category).addSuggestions(suggestions, status); + mSections.get(category).setSuggestions(suggestions, status, replaceExisting); } private boolean canLoadSuggestions(@CategoryInt int category, @CategoryStatusEnum int status) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java index 71b7d4b4..088ee0ac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -44,6 +44,13 @@ private boolean mIsNtpDestroyed; + // Keep track of impressions of the suggestions so that we replace only suggestions that + // have not been impressed, yet. We keep track of the first suggestion separately as the + // first is often impressed in the form of a peeking card and we still want to be able to + // replace something in this case. + private boolean mFirstSuggestionSeen; + private boolean mSubsequentSuggestionsSeen; + /** * Delegate interface that allows dismissing this section without introducing * a circular dependency. @@ -120,6 +127,17 @@ notifyItemRangeRemoved(0, itemCount); } + /** + * Clears all suggestions except the first one. + */ + private void clearAllButFirst() { + int itemCount = mSuggestions.size(); + if (itemCount > 1) { + mSuggestions.subList(1, itemCount).clear(); + notifyItemRangeRemoved(1, itemCount - 1); + } + } + public void addAll(List<SnippetArticle> suggestions) { if (suggestions.isEmpty()) return; @@ -228,6 +246,32 @@ if (child == mSuggestionsList) refreshChildrenVisibility(); } + @Override + public void onBindViewHolder(NewTabPageViewHolder holder, int position, List<Object> payloads) { + super.onBindViewHolder(holder, position, payloads); + childSeen(position); + } + + /** + * Sets the child at position {@code position} as being seen by the user. + * @param position Position in the list being shown (the first suggestion being at index 1, + * as at index 0, there is a non-suggestion). + */ + @VisibleForTesting + public void childSeen(int position) { + Log.d(TAG, "childSeen: position %d in category %d", position, mCategoryInfo.getCategory()); + assert getStartingOffsetForChild(mSuggestionsList) == 1; + if (getItemViewType(position) == ItemViewType.SNIPPET) { + // We assume all non-snippet cards come after all cards of type SNIPPET. + int positionAmongSuggestions = position - 1; + if (positionAmongSuggestions == 0) { + mFirstSuggestionSeen = true; + } else if (positionAmongSuggestions > 0) { + mSubsequentSuggestionsSeen = true; + } + } + } + /** * Removes a suggestion. Does nothing if the ID is unknown. * @param idWithinCategory The ID of the suggestion to remove. @@ -259,23 +303,51 @@ return suggestionIds; } - public void addSuggestions(List<SnippetArticle> suggestions, @CategoryStatusEnum int status) { + /** + * Puts {@code suggestions} into this section. It can either replace all existing suggestions + * with the new ones or append the new suggestions at the end of the list. This call may have no + * or only partial effect if changing the list of suggestions is not allowed (e.g. because the + * user has already seen the suggestions). + * @param suggestions The new list of suggestions for the given category. + * @param status The new category status. + * @param replaceExisting If true, {@code suggestions} replace the current list of suggestions. + * If false, {@code suggestions} are appended to current list of suggestions. + */ + public void setSuggestions(List<SnippetArticle> suggestions, @CategoryStatusEnum int status, + boolean replaceExisting) { + Log.d(TAG, "setSuggestions: previous number of suggestions: %d; replace existing: %b", + mSuggestionsList.getItemCount(), replaceExisting); if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestionsList.clear(); - mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); - Log.d(TAG, "addSuggestions: current number of suggestions: %d", - mSuggestionsList.getItemCount()); + // Remove suggestions to be replaced. + if (replaceExisting && hasSuggestions()) { + if (CardsVariationParameters.ignoreUpdatesForExistingSuggestions() + || mSubsequentSuggestionsSeen) { + Log.d(TAG, "setSuggestions: replacing existing suggestion not possible"); + return; + } - int sizeBefore = suggestions.size(); + if (mFirstSuggestionSeen) { + Log.d(TAG, "setSuggestions: keeping the first suggestion"); + mSuggestionsList.clearAllButFirst(); - // TODO(dgn): remove once the backend stops sending duplicates. - if (suggestions.removeAll(mSuggestionsList.mSuggestions)) { - Log.d(TAG, "addSuggestions: Removed duplicates from incoming suggestions. " - + "Count changed from %d to %d", - sizeBefore, suggestions.size()); + // Make sure that {@code mSuggestionsList} will contain as many elements as newly + // provided in {@code suggestions}. Remove the kept first element from the new + // collection, if it repeats there. Otherwise, remove the last element of the new + // collection. + if (!suggestions.remove(mSuggestionsList.getSuggestionAt(0))) { + suggestions.remove(suggestions.size() - 1); + } + } else { + Log.d(TAG, "setSuggestions: removing all suggestions"); + mSuggestionsList.clear(); + } } + mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); + mSuggestionsList.addAll(suggestions); + for (SnippetArticle article : suggestions) { if (!article.requiresExactOfflinePage()) { updateSnippetOfflineAvailability(article);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java index 2a60c30..63dcaf2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
@@ -168,6 +168,7 @@ return Collections.emptyList(); } List<SnippetArticle> result = mSuggestions.get(category); - return result == null ? Collections.<SnippetArticle>emptyList() : result; + return result == null ? Collections.<SnippetArticle>emptyList() + : new ArrayList<SnippetArticle>(result); } -} \ No newline at end of file +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java index 8d389d0..dbc2c624 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -179,8 +179,8 @@ // Include only local profiles, because GUIDs of server profiles change on every browser // restart. Server profiles are not supported as billing addresses. if (!profile.getIsLocal()) continue; - // Do not include profiles with empty billing address info. - if (TextUtils.isEmpty(profile.getLabel())) continue; + // Do not include profiles without street address. + if (TextUtils.isEmpty(profile.getStreetAddress())) continue; mProfilesForBillingAddress.add(profile); Pair<Integer, Integer> editMessageResIds = AutofillAddress.getEditMessageAndTitleResIds( AutofillAddress.checkAddressCompletionStatus(profile)); @@ -767,7 +767,7 @@ PersonalDataManager pdm = PersonalDataManager.getInstance(); if (!card.getIsLocal()) { - pdm.updateServerCardBillingAddress(card.getServerId(), card.getBillingAddressId()); + pdm.updateServerCardBillingAddress(card); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java index 5531401b..5fb89fb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java
@@ -14,7 +14,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.PersonalDataManager; -import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.customtabs.CustomTabActivity; /** @@ -91,8 +90,7 @@ @Override protected boolean saveEntry() { - PersonalDataManager.getInstance().updateServerCardBillingAddress(mCard.getServerId(), - ((AutofillProfile) mBillingAddress.getSelectedItem()).getGUID()); + PersonalDataManager.getInstance().updateServerCardBillingAddress(mCard); return true; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java index de9d183..64cf4d6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
@@ -69,11 +69,10 @@ "Maggie Doe", "Google", "340 Main St", "CA", "", "", "90291", "", "US", "", "jon.doe@gmail.com", "en-US")); - // Profile with empty billing address info (should not be presented to user). + // Profile with empty street address (should not be presented to user). String profile8 = helper.setProfile(new AutofillProfile("", "https://example.com", true, - "" /* fullName */, "" /* companyName */, "" /* streetAddress */, "" /* region */, - "" /* locality */, "" /* dependentLocality */, "" /* postalCode */, - "" /* sortingCode */, "US", "310-310-6000", "jon.doe@gmail.com", "en-US")); + "Jerry Doe", "Google", "" /* streetAddress */, "CA", "Los Angeles", "", "90291", "", + "US", "310-310-6000", "jerry.doe@gmail.com", "en-US")); // This card has no billing address selected. helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jane Doe",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java index 36f0bf7f..2c50fc0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -70,8 +70,8 @@ import org.chromium.testing.local.LocalRobolectricTestRunner; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -101,6 +101,7 @@ public final boolean mStatusCard; public boolean mActionButton; public boolean mProgressItem; + public SnippetArticle mFirstItem; public SectionDescriptor(int numSuggestions) { mNumSuggestions = numSuggestions; @@ -116,6 +117,11 @@ mProgressItem = true; return this; } + + public SectionDescriptor withFirstItem(SnippetArticle firstItem) { + mFirstItem = firstItem; + return this; + } } /** @@ -145,6 +151,15 @@ public void expect(SectionDescriptor descriptor) { expect(ItemViewType.HEADER); + + if (descriptor.mFirstItem != null) { + if (mTreeNode.getSuggestionAt(mCurrentIndex) != descriptor.mFirstItem) { + fail("Wrong snippet at position " + mCurrentIndex + "\n" + + explainFailedExpectation( + mTreeNode, mCurrentIndex, ItemViewType.SNIPPET)); + } + } + for (int i = 1; i <= descriptor.mNumSuggestions; i++) { expect(ItemViewType.SNIPPET); } @@ -174,6 +189,9 @@ ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application); + // Set empty variation params for the test. + CardsVariationParameters.setTestVariationParams(new HashMap<String, String>()); + // Initialise the sign in state. We will be signed in by default in the tests. assertFalse(ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .getNewTabPageSigninPromoDismissed()); @@ -219,18 +237,10 @@ mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); assertItemsFor(section(numSuggestions)); - - // The adapter should ignore any new incoming data. - mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, - Arrays.asList(new SnippetArticle[] { - new SnippetArticle(0, "foo", "title1", "pub1", "txt1", "url", 0, 0, 0)})); - - assertItemsFor(section(numSuggestions)); } /** - * Tests that the adapter keeps listening for suggestion updates if it didn't get anything from - * a previous fetch. + * Tests that the adapter keeps listening for suggestion updates. */ @Test @Feature({"Ntp"}) @@ -247,12 +257,6 @@ mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); assertItemsFor(section(numSuggestions)); - - // The adapter should ignore any new incoming data. - mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, - Arrays.asList(new SnippetArticle[] { - new SnippetArticle(0, "foo", "title1", "pub1", "txt1", "url", 0, 0, 0)})); - assertItemsFor(section(numSuggestions)); } /** @@ -296,12 +300,9 @@ mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); assertItemsFor(section(3)); - // If we have snippets, we should not load the new list (i.e. the extra item does *not* - // appear). + // Add another snippet. suggestions.add(new SnippetArticle(0, "https://site.com/url1", "title1", "pub1", "txt1", "https://site.com/url1", 0, 0, 0)); - mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); - assertItemsFor(section(3)); // When snippets are disabled, we should not be able to load them. mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); @@ -395,6 +396,72 @@ assertItemsFor(); } + /** + * Tests that the UI updates on updated suggestions. + */ + @Test + @Feature({"Ntp"}) + public void testUIUpdatesOnNewSuggestionsWhenOtherSectionSeen() { + List<SnippetArticle> snippets = createDummySuggestions(4); + mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); + mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + + List<SnippetArticle> bookmarks = createDummySuggestions(2); + mSource.setStatusForCategory(KnownCategories.BOOKMARKS, CategoryStatus.AVAILABLE); + mSource.setInfoForCategory(KnownCategories.BOOKMARKS, + new CategoryInfoBuilder(KnownCategories.BOOKMARKS).showIfEmpty().build()); + mSource.setSuggestionsForCategory(KnownCategories.BOOKMARKS, bookmarks); + + reloadNtp(); + assertItemsFor(section(4), section(2)); + + mAdapter.getSectionListForTesting() + .getSectionForTesting(KnownCategories.BOOKMARKS) + .childSeen(2); + + List<SnippetArticle> newSnippets = createDummySuggestions(3); + mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, newSnippets); + assertItemsFor(section(3), section(2)); + + reloadNtp(); + assertItemsFor(section(3), section(2)); + } + + /** + * Tests that the UI updates the first item of the section if the first item of some other + * section has been viewed. + */ + @Test + @Feature({"Ntp"}) + public void testUIUpdatesOnNewSuggestionsWhenFirstOfOtherSectionIsSeen() { + List<SnippetArticle> snippets = createDummySuggestions(4); + SnippetArticle earlier = snippets.get(0); + mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); + mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + + List<SnippetArticle> bookmarks = createDummySuggestions(1); + mSource.setStatusForCategory(KnownCategories.BOOKMARKS, CategoryStatus.AVAILABLE); + mSource.setInfoForCategory(KnownCategories.BOOKMARKS, + new CategoryInfoBuilder(KnownCategories.BOOKMARKS).showIfEmpty().build()); + mSource.setSuggestionsForCategory(KnownCategories.BOOKMARKS, bookmarks); + + reloadNtp(); + assertItemsFor(section(4), section(1)); + + mAdapter.getSectionListForTesting() + .getSectionForTesting(KnownCategories.BOOKMARKS) + .childSeen(1); + + List<SnippetArticle> newSnippets = createDummySuggestions(3); + SnippetArticle newer = newSnippets.get(0); + + mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, newSnippets); + assertItemsFor(section(3).withFirstItem(newer), section(1)); + + reloadNtp(); + assertItemsFor(section(3).withFirstItem(newer), section(1)); + } + /** Tests whether a section stays visible if empty, if required. */ @Test @Feature({"Ntp"}) @@ -687,7 +754,6 @@ reset(dataObserver); suggestionsSource.setSuggestionsForCategory( KnownCategories.ARTICLES, createDummySuggestions(newSuggestionCount)); - mAdapter.getSectionListForTesting().onNewSuggestions(KnownCategories.ARTICLES); verify(dataObserver).onItemRangeInserted(2, newSuggestionCount); verify(dataObserver).onItemRangeChanged(5 + newSuggestionCount, 1, null); // Spacer refresh verify(dataObserver, times(2)).onItemRangeRemoved(2 + newSuggestionCount, 1);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java index 7802f8ab..1336e85 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -42,6 +42,7 @@ import org.chromium.testing.local.LocalRobolectricTestRunner; import java.util.Arrays; +import java.util.HashMap; import java.util.List; /** @@ -61,6 +62,9 @@ public void setUp() { MockitoAnnotations.initMocks(this); mBridge = new FakeOfflinePageBridge(); + + // Set empty variation params for the test. + CardsVariationParameters.setTestVariationParams(new HashMap<String, String>()); } @Test @@ -79,7 +83,7 @@ assertEquals(1, section.getDismissSiblingPosDelta(1)); // With snippets. - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertEquals(ItemViewType.SNIPPET, section.getItemViewType(1)); assertEquals(0, section.getDismissSiblingPosDelta(1)); } @@ -99,7 +103,7 @@ assertEquals(2, section.getItemCount()); // When empty, we have the header and status card. assertEquals(ItemViewType.STATUS, section.getItemViewType(1)); - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); verify(mParent).onItemRangeInserted(section, 1, suggestionCount); verify(mParent).onItemRangeRemoved(section, 1 + suggestionCount, 1); } @@ -113,7 +117,7 @@ // Simulate initialisation by the adapter. Here we don't care about the notifications, since // the RecyclerView will be updated through notifyDataSetChanged. - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); reset(mParent); // We don't clear suggestions when the status is AVAILABLE. @@ -152,7 +156,7 @@ section.setStatus(CategoryStatus.AVAILABLE); reset(mParent); - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); section.removeSuggestionById(snippets.get(1).mIdWithinCategory); verify(mParent).onItemRangeRemoved(section, 2, 1); @@ -182,7 +186,7 @@ reset(mParent); assertEquals(3, section.getItemCount()); // We have the header and status card and a button. - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertEquals(4, section.getItemCount()); section.removeSuggestionById(snippets.get(0).mIdWithinCategory); @@ -228,7 +232,7 @@ mBridge.setItems(Arrays.asList(item0, item1)); SuggestionsSection section = createSectionWithReloadAction(true); - section.addSuggestions(snippets, CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); // Check that we pick up the correct information. assertEquals(Long.valueOf(0L), snippets.get(0).getOfflinePageOfflineId()); @@ -264,7 +268,8 @@ assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_VIEW_ALL); - section.addSuggestions(createDummySuggestions(3), CategoryStatus.AVAILABLE); + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_VIEW_ALL); @@ -288,7 +293,8 @@ assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_RELOAD); - section.addSuggestions(createDummySuggestions(3), CategoryStatus.AVAILABLE); + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_FETCH_MORE); @@ -307,7 +313,8 @@ assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_RELOAD); - section.addSuggestions(createDummySuggestions(3), CategoryStatus.AVAILABLE); + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertFalse(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_NONE); @@ -326,7 +333,8 @@ assertFalse(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_NONE); - section.addSuggestions(createDummySuggestions(3), CategoryStatus.AVAILABLE); + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertTrue(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_FETCH_MORE); @@ -344,7 +352,8 @@ assertFalse(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_NONE); - section.addSuggestions(createDummySuggestions(3), CategoryStatus.AVAILABLE); + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); assertFalse(section.getActionItem().isVisible()); verifyAction(section, ActionItem.ACTION_NONE); @@ -357,7 +366,8 @@ SuggestionsCategoryInfo info = spy(new CategoryInfoBuilder(42).withMoreAction().showIfEmpty().build()); SuggestionsSection section = createSection(info); - section.addSuggestions(createDummySuggestions(suggestionCount), CategoryStatus.AVAILABLE); + section.setSuggestions(createDummySuggestions(suggestionCount), CategoryStatus.AVAILABLE, + /* replaceExisting = */ true); assertFalse(section.getProgressItemForTesting().isVisible()); // Tap the button @@ -365,10 +375,86 @@ assertTrue(section.getProgressItemForTesting().isVisible()); // Simulate receiving suggestions. - section.addSuggestions(createDummySuggestions(suggestionCount), CategoryStatus.AVAILABLE); + section.setSuggestions(createDummySuggestions(suggestionCount), CategoryStatus.AVAILABLE, + /* replaceExisting = */ false); assertFalse(section.getProgressItemForTesting().isVisible()); } + /** + * Tests that the UI updates on updated suggestions. + */ + @Test + @Feature({"Ntp"}) + public void testSectionUpdatesOnNewSuggestions() { + SuggestionsSection section = createSectionWithSuggestions(createDummySuggestions(4)); + assertEquals(4, section.getSuggestionsCount()); + + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); + assertEquals(3, section.getSuggestionsCount()); + } + + /** + * Tests that the UI does not update when updating is disabled by a parameter. + */ + @Test + @Feature({"Ntp"}) + public void testSectionDoesNotUpdateOnNewSuggestionsWhenDisabled() { + // Override variation params for the test. + HashMap<String, String> params = new HashMap<String, String>(); + params.put("ignore_updates_for_existing_suggestions", "true"); + CardsVariationParameters.setTestVariationParams(params); + + SuggestionsSection section = createSectionWithSuggestions(createDummySuggestions(4)); + assertEquals(4, section.getSuggestionsCount()); + + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); + assertEquals(4, section.getSuggestionsCount()); + } + + /** + * Tests that the UI does not update when the section has been viewed. + */ + @Test + @Feature({"Ntp"}) + public void testSectionDoesNotUpdateOnNewSuggestionsWhenSectionSeen() { + SuggestionsSection section = createSectionWithSuggestions(createDummySuggestions(4)); + assertEquals(4, section.getSuggestionsCount()); + + section.childSeen(2); + + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); + assertEquals(4, section.getSuggestionsCount()); + } + + /** + * Tests that the UI does not update the first item of the section if it has been viewed. + */ + @Test + @Feature({"Ntp"}) + public void testSectionDoesNotUpdateFirstSuggestionOnNewSuggestionsWhenSeen() { + List<SnippetArticle> snippets = createDummySuggestions(4); + SnippetArticle firstFromOriginalList = snippets.get(0); + SuggestionsSection section = createSectionWithSuggestions(snippets); + assertEquals(4, section.getSuggestionsCount()); + + section.childSeen(1); + + section.setSuggestions( + createDummySuggestions(3), CategoryStatus.AVAILABLE, /* replaceExisting = */ true); + assertEquals(3, section.getSuggestionsCount()); + assertEquals(firstFromOriginalList, section.getSuggestionAt(1)); + } + + private SuggestionsSection createSectionWithSuggestions(List<SnippetArticle> snippets) { + SuggestionsSection section = createSectionWithReloadAction(true); + section.setStatus(CategoryStatus.AVAILABLE); + section.setSuggestions(snippets, CategoryStatus.AVAILABLE, /* replaceExisting = */ true); + return section; + } + private SuggestionsSection createSectionWithReloadAction(boolean hasReloadAction) { CategoryInfoBuilder builder = new CategoryInfoBuilder(42).showIfEmpty(); if (hasReloadAction) builder.withReloadAction();
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc index 962c8232..8148716 100644 --- a/chrome/app/chrome_crash_reporter_client_win.cc +++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -253,7 +253,10 @@ std::wstring process_type = install_static::GetSwitchValueFromCommandLine( ::GetCommandLine(), install_static::kProcessType); - if (process_type != install_static::kCrashpadHandler) { + // Don't set up Crashpad crash reporting in the Crashpad handler itself, nor + // in the fallback crash handler for the Crashpad handler process. + if (process_type != install_static::kCrashpadHandler && + process_type != install_static::kFallbackHandler) { crash_reporter::SetCrashReporterClient(instance); crash_reporter::InitializeCrashpadWithEmbeddedHandler( process_type.empty(), install_static::UTF16ToUTF8(process_type));
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc index b95c04a..9d135f0 100644 --- a/chrome/app/chrome_exe_main_win.cc +++ b/chrome/app/chrome_exe_main_win.cc
@@ -19,6 +19,7 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/win/registry.h" #include "base/win/windows_version.h" @@ -29,9 +30,11 @@ #include "chrome/common/chrome_paths_internal.h" #include "chrome/common/chrome_switches.h" #include "chrome/install_static/install_details.h" +#include "chrome/install_static/install_util.h" #include "chrome_elf/chrome_elf_main.h" #include "components/crash/content/app/crash_switches.h" #include "components/crash/content/app/crashpad.h" +#include "components/crash/content/app/fallback_crash_handling_win.h" #include "components/crash/content/app/run_as_crashpad_handler_win.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" @@ -196,6 +199,24 @@ return false; } +int RunFallbackCrashHandler(const base::CommandLine& cmd_line) { + // Retrieve the product & version details we need to report the crash + // correctly. + wchar_t exe_file[MAX_PATH] = {}; + CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file))); + + base::string16 product_name; + base::string16 version; + base::string16 channel_name; + base::string16 special_build; + install_static::GetExecutableVersionDetails(exe_file, &product_name, &version, + &special_build, &channel_name); + + return crash_reporter::RunAsFallbackCrashHandler( + cmd_line, base::UTF16ToUTF8(product_name), base::UTF16ToUTF8(version), + base::UTF16ToUTF8(channel_name)); +} + } // namespace #if defined(SYZYASAN) @@ -228,8 +249,11 @@ HasValidWindowsPrefetchArgument(*command_line)); if (process_type == crash_reporter::switches::kCrashpadHandler) { + crash_reporter::SetupFallbackCrashHandling(*command_line); return crash_reporter::RunAsCrashpadHandler( *base::CommandLine::ForCurrentProcess()); + } else if (process_type == crash_reporter::switches::kFallbackCrashHandler) { + return RunFallbackCrashHandler(*command_line); } const base::TimeTicks exe_entry_point_ticks = base::TimeTicks::Now();
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 7b064d6..5bc655f5 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -6201,6 +6201,9 @@ <message name="IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH" desc="Error message shown on the enrollment screen when the system failed to fetch device policy from Active Directory."> Oops! The system failed to fetch policy from Microsoft® Active Directory®. </message> + <message name="IDS_ENTERPRISE_ENROLLMENT_ERROR_STORE_DM_TOKEN_FAILED" desc="Error message shown on the enrollment screen when the system failed to store DM token into the local state."> + Oops! The system failed to store DM token on the device. + </message> <message name="IDS_ENTERPRISE_ENROLLMENT_SCREEN_TITLE" desc="The title on the enterprise enrollment dialog."> Enterprise enrollment </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 0ff9de1..9b4acd1 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -261,10 +261,6 @@ "component_updater/sw_reporter_installer_win.h", "component_updater/swiftshader_component_installer.cc", "component_updater/swiftshader_component_installer.h", - "conflicts/module_database_win.cc", - "conflicts/module_database_win.h", - "conflicts/module_event_sink_impl_win.cc", - "conflicts/module_event_sink_impl_win.h", "content_settings/chrome_content_settings_utils.cc", "content_settings/chrome_content_settings_utils.h", "content_settings/cookie_settings_factory.cc",
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc index 935ffa1..72d1c16 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -112,12 +112,12 @@ } InstallableParams params; - params.ideal_icon_size_in_px = + params.ideal_primary_icon_size_in_px = ShortcutHelper::GetIdealHomescreenIconSizeInPx(); - params.minimum_icon_size_in_px = + params.minimum_primary_icon_size_in_px = ShortcutHelper::GetMinimumHomescreenIconSizeInPx(); params.check_installable = true; - params.fetch_valid_icon = true; + params.fetch_valid_primary_icon = true; InstallableManager::CreateForWebContents(web_contents()); InstallableManager* installable_manager = InstallableManager::FromWebContents(web_contents()); @@ -152,15 +152,15 @@ info_.UpdateFromManifest(data.manifest); info_.manifest_url = data.manifest_url; - info_.best_icon_url = data.icon_url; - best_icon_ = *data.icon; + info_.best_icon_url = data.primary_icon_url; + best_icon_ = *data.primary_icon; icon_hasher_.reset(new WebApkIconHasher()); Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); icon_hasher_->DownloadAndComputeMurmur2Hash( profile->GetRequestContext(), - data.icon_url, + data.primary_icon_url, base::Bind(&WebApkUpdateDataFetcher::OnGotIconMurmur2Hash, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index 155aadaf..a29a5c4 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -47,10 +47,10 @@ int minimum_icon_size_in_px, bool check_installable) { InstallableParams params; - params.ideal_icon_size_in_px = ideal_icon_size_in_px; - params.minimum_icon_size_in_px = minimum_icon_size_in_px; + params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px; + params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px; params.check_installable = check_installable; - params.fetch_valid_icon = true; + params.fetch_valid_primary_icon = true; return params; } @@ -218,10 +218,10 @@ weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title); - if (data.icon) { - shortcut_info_.best_icon_url = data.icon_url; + if (data.primary_icon) { + shortcut_info_.best_icon_url = data.primary_icon_url; - CreateLauncherIcon(*(data.icon)); + CreateLauncherIcon(*(data.primary_icon)); return; }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index 3103b17..ddfa514f 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -17,10 +17,10 @@ #include "chrome/browser/android/webapk/webapk_install_service.h" #include "chrome/browser/android/webapk/webapk_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" +#include "chrome/browser/installable/installable_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/origin_util.h" #include "jni/AddToHomescreenManager_jni.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -77,7 +77,7 @@ void AddToHomescreenManager::Start(content::WebContents* web_contents) { bool check_webapk_compatible = false; if (ChromeWebApkHost::AreWebApkEnabled() && - content::IsOriginSecure(web_contents->GetLastCommittedURL())) { + InstallableManager::IsContentSecure(web_contents)) { check_webapk_compatible = true; } else { ShowDialog();
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc index 3a5ad19..782f25cf7 100644 --- a/chrome/browser/autofill/android/personal_data_manager_android.cc +++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -532,14 +532,11 @@ void PersonalDataManagerAndroid::UpdateServerCardBillingAddress( JNIEnv* env, const JavaParamRef<jobject>& unused_obj, - const JavaParamRef<jstring>& jcard_server_id, - const JavaParamRef<jstring>& jbilling_address_id) { - CreditCard card("", kSettingsOrigin); - card.set_record_type(CreditCard::MASKED_SERVER_CARD); - card.set_server_id(ConvertJavaStringToUTF8(env, jcard_server_id)); - card.set_billing_address_id(ConvertJavaStringToUTF8(env, - jbilling_address_id)); - personal_data_manager_->UpdateServerCardBillingAddress(card); + const JavaParamRef<jobject>& jcard) { + CreditCard card; + PopulateNativeCreditCardFromJava(jcard, env, &card); + + personal_data_manager_->UpdateServerCardMetadata(card); } ScopedJavaLocalRef<jstring> PersonalDataManagerAndroid::GetBasicCardPaymentType(
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.h b/chrome/browser/autofill/android/personal_data_manager_android.h index 5f48ea0..2b3becc 100644 --- a/chrome/browser/autofill/android/personal_data_manager_android.h +++ b/chrome/browser/autofill/android/personal_data_manager_android.h
@@ -161,13 +161,11 @@ const base::android::JavaParamRef<jobject>& unused_obj, const base::android::JavaParamRef<jobject>& jcard); - // Updates the billing address of a server credit card with server ID - // |jcard_server_id|. + // Updates the billing address of a server credit card |jcard|. void UpdateServerCardBillingAddress( JNIEnv* env, const base::android::JavaParamRef<jobject>& unused_obj, - const base::android::JavaParamRef<jstring>& jcard_server_id, - const base::android::JavaParamRef<jstring>& jbilling_address_id); + const base::android::JavaParamRef<jobject>& jcard); // Returns the card type according to PaymentRequest spec, or an empty string // if the given card number is not valid and |jempty_if_invalid| is true.
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc index 908b932..dfd57ea 100644 --- a/chrome/browser/banners/app_banner_manager.cc +++ b/chrome/browser/banners/app_banner_manager.cc
@@ -22,7 +22,6 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/origin_util.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/modules/installation/installation.mojom.h" @@ -42,10 +41,10 @@ InstallableParams ParamsToPerformInstallableCheck(int ideal_icon_size_in_px, int minimum_icon_size_in_px) { InstallableParams params; - params.ideal_icon_size_in_px = ideal_icon_size_in_px; - params.minimum_icon_size_in_px = minimum_icon_size_in_px; + params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px; + params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px; params.check_installable = true; - params.fetch_valid_icon = true; + params.fetch_valid_primary_icon = true; return params; } @@ -106,7 +105,7 @@ // A secure origin is required to show banners, so exit early if we see the // URL is invalid. - if (!content::IsOriginSecure(validated_url)) { + if (!InstallableManager::IsContentSecure(contents)) { ReportStatus(contents, NOT_FROM_SECURE_ORIGIN); Stop(); return; @@ -267,11 +266,11 @@ return; DCHECK(data.is_installable); - DCHECK(!data.icon_url.is_empty()); - DCHECK(data.icon); + DCHECK(!data.primary_icon_url.is_empty()); + DCHECK(data.primary_icon); - icon_url_ = data.icon_url; - icon_.reset(new SkBitmap(*data.icon)); + icon_url_ = data.primary_icon_url; + icon_.reset(new SkBitmap(*data.primary_icon)); SendBannerPromptRequest(); }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 9659be9..4a6c5b79e 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1078,6 +1078,8 @@ "policy/device_status_collector.h", "policy/display_rotation_default_handler.cc", "policy/display_rotation_default_handler.h", + "policy/dm_token_storage.cc", + "policy/dm_token_storage.h", "policy/enrollment_config.h", "policy/enrollment_handler_chromeos.cc", "policy/enrollment_handler_chromeos.h", @@ -1595,6 +1597,7 @@ "policy/device_cloud_policy_manager_chromeos_unittest.cc", "policy/device_cloud_policy_store_chromeos_unittest.cc", "policy/device_local_account_policy_service_unittest.cc", + "policy/dm_token_storage_unittest.cc", "policy/extension_cache_unittest.cc", "policy/fake_affiliated_invalidation_service_provider.cc", "policy/fake_affiliated_invalidation_service_provider.h",
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc index 24c24d5..74b8913e 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -253,7 +253,13 @@ ArcSessionManager::Get()->state()); } -IN_PROC_BROWSER_TEST_F(ArcSessionManagerTest, ManagedAndroidAccount) { +#if defined(OS_CHROMEOS) +// https://crbug.com/681547 - flaky segfault on linux_chromium_chromeos_rel_ng +#define MAYBE_ManagedAndroidAccount DISABLED_ManagedAndroidAccount +#else +#define MAYBE_ManagedAndroidAccount ManagedAndroidAccount +#endif +IN_PROC_BROWSER_TEST_F(ArcSessionManagerTest, MAYBE_ManagedAndroidAccount) { EnableArc(); token_service()->IssueTokenForAllPendingRequests(kManagedAuthToken, base::Time::Max());
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc index 999c676a..261516ff 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc
@@ -13,7 +13,7 @@ } // namespace const base::Feature kMediaViewFeature{"ArcMediaView", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; const char kMediaDocumentsProviderAuthority[] = "com.android.providers.media.documents";
diff --git a/chrome/browser/chromeos/drive/download_handler.cc b/chrome/browser/chromeos/drive/download_handler.cc index 9502b8c..42e2303 100644 --- a/chrome/browser/chromeos/drive/download_handler.cc +++ b/chrome/browser/chromeos/drive/download_handler.cc
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/strings/string_util.h" #include "base/supports_user_data.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" @@ -377,9 +378,8 @@ FileError error) { DVLOG(1) << "OnCreateDirectory " << FileErrorToString(error); if (error == FILE_ERROR_OK) { - base::PostTaskAndReplyWithResult( - BrowserThread::GetBlockingPool(), - FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock(), base::Bind(&GetDriveTempDownloadPath, drive_tmp_download_path_), callback); } else {
diff --git a/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc b/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc index ca54162..fb745cd 100644 --- a/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc +++ b/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc
@@ -9,8 +9,7 @@ #include "base/files/file_path.h" #include "base/logging.h" -#include "base/task_runner_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "components/drive/chromeos/file_system_interface.h" @@ -185,11 +184,10 @@ } // Cache file prepared for modification is available. Open it locally. - bool posted = base::PostTaskAndReplyWithResult( - BrowserThread::GetBlockingPool(), FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock(), base::Bind(&OpenFile, local_path, file_flags), base::Bind(&RunOpenFileCallback, callback, close_callback)); - DCHECK(posted); } } // namespace
diff --git a/chrome/browser/chromeos/file_manager/open_with_browser.cc b/chrome/browser/chromeos/file_manager/open_with_browser.cc index 8da982e2..eb9352d 100644 --- a/chrome/browser/chromeos/file_manager/open_with_browser.cc +++ b/chrome/browser/chromeos/file_manager/open_with_browser.cc
@@ -11,7 +11,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/path_service.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" #include "chrome/browser/chromeos/fileapi/external_file_url_util.h" @@ -127,7 +127,7 @@ // Reads the alternate URL from a GDoc file. When it fails, returns a file URL // for |file_path| as fallback. // Note that an alternate url is a URL to open a hosted document. -GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) { +GURL ReadUrlFromGDocAsync(const base::FilePath& file_path) { GURL url = drive::util::ReadUrlFromGDocFile(file_path); if (url.is_empty()) url = net::FilePathToFileURL(file_path); @@ -169,10 +169,9 @@ } else { // The file is local (downloaded from an attachment or otherwise copied). // Parse the file to extract the Docs url and open this url. - base::PostTaskAndReplyWithResult( - BrowserThread::GetBlockingPool(), - FROM_HERE, - base::Bind(&ReadUrlFromGDocOnBlockingPool, file_path), + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock(), + base::Bind(&ReadUrlFromGDocAsync, file_path), base::Bind(&OpenNewTab, profile)); } return true;
diff --git a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc index 11b741f..fde8ecc5 100644 --- a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc +++ b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -418,6 +418,9 @@ case policy::EnrollmentStatus::ACTIVE_DIRECTORY_POLICY_FETCH_FAILED: UMA(policy::kMetricEnrollmentActiveDirectoryPolicyFetchFailed); break; + case policy::EnrollmentStatus::DM_TOKEN_STORE_FAILED: + UMA(policy::kMetricEnrollmentStoreDMTokenFailed); + break; } }
diff --git a/chrome/browser/chromeos/policy/dm_token_storage.cc b/chrome/browser/chromeos/policy/dm_token_storage.cc new file mode 100644 index 0000000..b3baeeb --- /dev/null +++ b/chrome/browser/chromeos/policy/dm_token_storage.cc
@@ -0,0 +1,184 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/policy/dm_token_storage.h" + +#include "base/bind.h" +#include "chrome/browser/chromeos/settings/token_encryptor.h" +#include "chrome/common/pref_names.h" +#include "chromeos/cryptohome/system_salt_getter.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" + +namespace { + +std::string EncryptToken(const std::string& system_salt, + const std::string& dm_token) { + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); + chromeos::CryptohomeTokenEncryptor encryptor(system_salt); + return encryptor.EncryptWithSystemSalt(dm_token); +} + +std::string DecryptToken(const std::string& system_salt, + const std::string encrypted_dm_token) { + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); + chromeos::CryptohomeTokenEncryptor encryptor(system_salt); + return encryptor.DecryptWithSystemSalt(encrypted_dm_token); +} + +} // namespace + +namespace policy { + +DMTokenStorage::DMTokenStorage(PrefService* local_state) + : local_state_(local_state), weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::Bind( + &DMTokenStorage::OnSystemSaltRecevied, weak_ptr_factory_.GetWeakPtr())); +} + +DMTokenStorage::~DMTokenStorage() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + FlushStoreTokenCallback(false); + FlushRetrieveTokenCallback(std::string()); +} + +// static +void DMTokenStorage::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterStringPref(prefs::kDeviceDMToken, std::string()); +} + +void DMTokenStorage::StoreDMToken(const std::string& dm_token, + StoreCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!store_callback_.is_null()) { + DLOG(ERROR) + << "Failed to store DM token: Previous store operation is not finished"; + std::move(callback).Run(false); + return; + } + if (!retrieve_callbacks_.empty()) { + DLOG(ERROR) + << "Failed to store DM token: Retrieve operation is not finished"; + std::move(callback).Run(false); + return; + } + store_callback_ = std::move(callback); + dm_token_ = dm_token; + switch (state_) { + case SaltState::LOADING: + // Do nothing. Waiting for system salt. + break; + case SaltState::LOADED: + EncryptAndStoreToken(); + break; + case SaltState::ERROR: + FlushStoreTokenCallback(false); + break; + } +} + +void DMTokenStorage::RetrieveDMToken(RetrieveCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!store_callback_.is_null()) { + DCHECK(retrieve_callbacks_.empty()); + DLOG(ERROR) + << "Failed to retrieve DM token: Store operation is not finished"; + std::move(callback).Run(std::string()); + return; + } + retrieve_callbacks_.push_back(std::move(callback)); + switch (state_) { + case SaltState::LOADING: + // Do nothing. Waiting for system salt. + break; + case SaltState::LOADED: + if (retrieve_callbacks_.size() == 1) { // First consumer. + LoadAndDecryptToken(); + } + break; + case SaltState::ERROR: + FlushRetrieveTokenCallback(std::string()); + break; + } +} + +void DMTokenStorage::OnSystemSaltRecevied(const std::string& system_salt) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + system_salt_ = system_salt; + if (system_salt_.empty()) { + state_ = SaltState::ERROR; + DLOG(ERROR) << "Failed to get system salt."; + FlushStoreTokenCallback(false); + FlushRetrieveTokenCallback(std::string()); + return; + } + // Should not be concurrent store and get operations. + DCHECK(store_callback_.is_null() || retrieve_callbacks_.empty()); + state_ = SaltState::LOADED; + if (!store_callback_.is_null()) + EncryptAndStoreToken(); + else if (!retrieve_callbacks_.empty()) + LoadAndDecryptToken(); +} + +void DMTokenStorage::EncryptAndStoreToken() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!system_salt_.empty()); + DCHECK(!dm_token_.empty()); + base::PostTaskAndReplyWithResult( + content::BrowserThread::GetBlockingPool(), FROM_HERE, + base::Bind(&EncryptToken, system_salt_, dm_token_), + base::Bind(&DMTokenStorage::OnTokenEncrypted, + weak_ptr_factory_.GetWeakPtr())); +} + +void DMTokenStorage::OnTokenEncrypted(const std::string& encrypted_dm_token) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (encrypted_dm_token.empty()) { + DLOG(ERROR) << "Failed to encrypt DM token."; + } else { + local_state_->SetString(prefs::kDeviceDMToken, encrypted_dm_token); + } + FlushStoreTokenCallback(!encrypted_dm_token.empty()); +} + +void DMTokenStorage::LoadAndDecryptToken() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK_EQ(SaltState::LOADED, state_); + std::string encrypted_dm_token = + local_state_->GetString(prefs::kDeviceDMToken); + if (!encrypted_dm_token.empty()) { + base::PostTaskAndReplyWithResult( + content::BrowserThread::GetBlockingPool(), FROM_HERE, + base::Bind(&DecryptToken, system_salt_, encrypted_dm_token), + base::Bind(&DMTokenStorage::FlushRetrieveTokenCallback, + weak_ptr_factory_.GetWeakPtr())); + } else { + DLOG(ERROR) << "No DM token in the local state."; + FlushRetrieveTokenCallback(std::string()); + } +} + +void DMTokenStorage::FlushStoreTokenCallback(bool status) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!store_callback_.is_null()) { + std::move(store_callback_).Run(status); + } +} + +void DMTokenStorage::FlushRetrieveTokenCallback(const std::string& dm_token) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (retrieve_callbacks_.empty()) + return; + if (dm_token.empty()) + DLOG(ERROR) << "Failed to retrieve DM token."; + std::vector<RetrieveCallback> callbacks; + callbacks.swap(retrieve_callbacks_); + for (RetrieveCallback& callback : callbacks) + std::move(callback).Run(dm_token); +} + +} // namespace policy
diff --git a/chrome/browser/chromeos/policy/dm_token_storage.h b/chrome/browser/chromeos/policy/dm_token_storage.h new file mode 100644 index 0000000..19f3c910 --- /dev/null +++ b/chrome/browser/chromeos/policy/dm_token_storage.h
@@ -0,0 +1,87 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DM_TOKEN_STORAGE_H_ +#define CHROME_BROWSER_CHROMEOS_POLICY_DM_TOKEN_STORAGE_H_ + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" + +class PrefRegistrySimple; +class PrefService; + +namespace policy { + +// Helper class to store/retrieve DM token to/from the local state. This is +// needed for Active Directory management because AD devices lacks DM token in +// the policies. DM token will be used in the future for ARC++ integration. +// +// Note that requests must be made from the UI thread because SystemSaltGetter +// calls CryptohomeClient which must be called from the UI thread. +class DMTokenStorage { + public: + using StoreCallback = base::OnceCallback<void(bool success)>; + using RetrieveCallback = + base::OnceCallback<void(const std::string& dm_token)>; + + explicit DMTokenStorage(PrefService* local_state); + ~DMTokenStorage(); + + static void RegisterPrefs(PrefRegistrySimple* registry); + + // Persists |dm_token| on the device. Overwrites any previous value. Signals + // completion via |callback|, passing true if the operation succeeded. Fails + // if another operation is running (store or retrieve). + void StoreDMToken(const std::string& dm_token, StoreCallback callback); + + // Loads DM token from the local state and decrypts it. Fires callback on + // completion. Empty |dm_token| means error. Calls |callback| with empty token + // if store operation is running. + void RetrieveDMToken(RetrieveCallback callback); + + private: + enum class SaltState { + // Pending system salt. + LOADING, + // Failed to load system salt. + ERROR, + // System salt is loaded. + LOADED, + }; + + // Callback for SystemSaltRetrieveter. + void OnSystemSaltRecevied(const std::string& system_salt); + + // Encrypts DM token using system salt and stores it into the local state. + void EncryptAndStoreToken(); + + // Callback waiting for DM token to be encrypted. + void OnTokenEncrypted(const std::string& encrypted_dm_token); + + // Loads encrypted DM token from the local state and decrypts it using system + // salt. + void LoadAndDecryptToken(); + + // Fires StoreCallback (if exists) with the status. + void FlushStoreTokenCallback(bool status); + + // Fires RetrieveCallbacks (if exists) with |dm_token|. + void FlushRetrieveTokenCallback(const std::string& dm_token); + + PrefService* local_state_; + SaltState state_ = SaltState::LOADING; + std::string system_salt_; + // Stored |dm_token| while waiting for system salt. + std::string dm_token_; + StoreCallback store_callback_; + std::vector<RetrieveCallback> retrieve_callbacks_; + base::WeakPtrFactory<DMTokenStorage> weak_ptr_factory_; +}; + +} // namespace policy + +#endif // CHROME_BROWSER_CHROMEOS_POLICY_DM_TOKEN_STORAGE_H_
diff --git a/chrome/browser/chromeos/policy/dm_token_storage_unittest.cc b/chrome/browser/chromeos/policy/dm_token_storage_unittest.cc new file mode 100644 index 0000000..bce508e --- /dev/null +++ b/chrome/browser/chromeos/policy/dm_token_storage_unittest.cc
@@ -0,0 +1,233 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/policy/dm_token_storage.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chromeos/cryptohome/system_salt_getter.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_cryptohome_client.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace policy { + +class DMTokenStorageTest : public testing::Test { + public: + DMTokenStorageTest() + : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {} + ~DMTokenStorageTest() override {} + + void SetSaltPending() { + // Clear the cached salt. + chromeos::SystemSaltGetter::Shutdown(); + fake_cryptohome_client_->set_system_salt(std::vector<uint8_t>()); + fake_cryptohome_client_->SetServiceIsAvailable(false); + chromeos::SystemSaltGetter::Initialize(); + } + + void SetSaltAvailable() { + fake_cryptohome_client_->set_system_salt( + chromeos::FakeCryptohomeClient::GetStubSystemSalt()); + fake_cryptohome_client_->SetServiceIsAvailable(true); + } + + void SetSaltError() { + fake_cryptohome_client_->set_system_salt(std::vector<uint8_t>()); + fake_cryptohome_client_->SetServiceIsAvailable(true); + } + + void SetUp() override { + fake_cryptohome_client_ = new chromeos::FakeCryptohomeClient; + SetSaltAvailable(); + chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient( + std::unique_ptr<chromeos::CryptohomeClient>(fake_cryptohome_client_)); + + chromeos::SystemSaltGetter::Initialize(); + } + + void TearDown() override { + dm_token_storage_.reset(); + chromeos::SystemSaltGetter::Shutdown(); + chromeos::DBusThreadManager::Shutdown(); + base::RunLoop().RunUntilIdle(); + } + + void CreateDMStorage() { + dm_token_storage_ = + base::MakeUnique<DMTokenStorage>(scoped_testing_local_state_.Get()); + } + + void StoreDMToken() { + base::RunLoop run_loop; + dm_token_storage_->StoreDMToken( + "test-token", + base::Bind(&DMTokenStorageTest::OnStoreCallback, base::Unretained(this), + run_loop.QuitClosure(), true)); + run_loop.Run(); + } + + void OnStoreCallback(const base::Closure& closure, + bool expected, + bool success) { + EXPECT_EQ(expected, success); + if (!closure.is_null()) + closure.Run(); + } + + void OnRetrieveCallback(const base::Closure& closure, + const std::string& expected, + const std::string& actual) { + EXPECT_EQ(expected, actual); + if (!closure.is_null()) + closure.Run(); + } + + content::TestBrowserThreadBundle thread_bundle_; + ScopedTestingLocalState scoped_testing_local_state_; + chromeos::FakeCryptohomeClient* fake_cryptohome_client_; + std::unique_ptr<DMTokenStorage> dm_token_storage_; +}; + +TEST_F(DMTokenStorageTest, SaveEncryptedToken) { + CreateDMStorage(); + StoreDMToken(); + + { + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken(base::Bind( + &DMTokenStorageTest::OnRetrieveCallback, base::Unretained(this), + run_loop.QuitClosure(), "test-token")); + run_loop.Run(); + } + // Reload shouldn't change the token. + CreateDMStorage(); + { + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken(base::Bind( + &DMTokenStorageTest::OnRetrieveCallback, base::Unretained(this), + run_loop.QuitClosure(), "test-token")); + run_loop.Run(); + } + { + // Subsequent retrieving DM token should succeed. + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken(base::Bind( + &DMTokenStorageTest::OnRetrieveCallback, base::Unretained(this), + run_loop.QuitClosure(), "test-token")); + run_loop.Run(); + } +} + +TEST_F(DMTokenStorageTest, RetrieveEncryptedTokenWithPendingSalt) { + CreateDMStorage(); + StoreDMToken(); + + SetSaltPending(); + CreateDMStorage(); + + { + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken(base::Bind( + &DMTokenStorageTest::OnRetrieveCallback, base::Unretained(this), + run_loop.QuitClosure(), "test-token")); + SetSaltAvailable(); + run_loop.Run(); + } +} + +TEST_F(DMTokenStorageTest, StoreEncryptedTokenWithPendingSalt) { + SetSaltPending(); + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->StoreDMToken( + "test-token", + base::Bind(&DMTokenStorageTest::OnStoreCallback, base::Unretained(this), + run_loop.QuitClosure(), true)); + SetSaltAvailable(); + run_loop.Run(); +} + +TEST_F(DMTokenStorageTest, MultipleRetrieveTokenCalls) { + CreateDMStorage(); + StoreDMToken(); + { + base::RunLoop run_loop; + for (int i = 0; i < 3; ++i) { + dm_token_storage_->RetrieveDMToken(base::Bind( + &DMTokenStorageTest::OnRetrieveCallback, base::Unretained(this), + run_loop.QuitClosure(), "test-token")); + } + run_loop.Run(); + } +} + +TEST_F(DMTokenStorageTest, StoreWithSaltError) { + SetSaltError(); + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->StoreDMToken( + "test-token", + base::Bind(&DMTokenStorageTest::OnStoreCallback, base::Unretained(this), + run_loop.QuitClosure(), false)); + run_loop.Run(); +} + +TEST_F(DMTokenStorageTest, RetrieveWithSaltError) { + CreateDMStorage(); + StoreDMToken(); + SetSaltPending(); + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken( + base::Bind(&DMTokenStorageTest::OnRetrieveCallback, + base::Unretained(this), run_loop.QuitClosure(), "")); + SetSaltError(); + run_loop.Run(); +} + +TEST_F(DMTokenStorageTest, RetrieveWithNoToken) { + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->RetrieveDMToken( + base::Bind(&DMTokenStorageTest::OnRetrieveCallback, + base::Unretained(this), run_loop.QuitClosure(), "")); + run_loop.Run(); +} + +TEST_F(DMTokenStorageTest, RetrieveFailIfStoreRunning) { + SetSaltPending(); + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->StoreDMToken( + "test-token", + base::Bind(&DMTokenStorageTest::OnStoreCallback, base::Unretained(this), + run_loop.QuitClosure(), true)); + dm_token_storage_->RetrieveDMToken( + base::Bind(&DMTokenStorageTest::OnRetrieveCallback, + base::Unretained(this), base::Closure(), "")); + SetSaltAvailable(); + run_loop.Run(); +} + +TEST_F(DMTokenStorageTest, StoreFailIfAnotherStoreRunning) { + SetSaltPending(); + CreateDMStorage(); + base::RunLoop run_loop; + dm_token_storage_->StoreDMToken( + "test-token", + base::Bind(&DMTokenStorageTest::OnStoreCallback, base::Unretained(this), + run_loop.QuitClosure(), true)); + dm_token_storage_->StoreDMToken( + "test-token", base::Bind(&DMTokenStorageTest::OnStoreCallback, + base::Unretained(this), base::Closure(), false)); + SetSaltAvailable(); + run_loop.Run(); +} + +} // namespace policy
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc index 7aceb11..6be059dd 100644 --- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc +++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h" +#include "chrome/browser/chromeos/policy/dm_token_storage.h" #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h" @@ -244,14 +245,6 @@ void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) { DCHECK_EQ(store_, store); - if (enrollment_step_ == STEP_STORE_TOKEN_AND_ID) { - // Calling OwnerSettingsServiceChromeOS::SetManagementSettings() - // on a non- enterprise-managed device will fail as - // DeviceCloudPolicyStore listens to all changes on device - // settings, and it calls OnStoreError() when the device is not - // enterprise-managed. - return; - } LOG(ERROR) << "Error in device policy store."; ReportResult(EnrollmentStatus::ForStoreError(store_->status(), store_->validation_status())); @@ -423,12 +416,27 @@ weak_ptr_factory_.GetWeakPtr())); } +void EnrollmentHandlerChromeOS::HandleDMTokenStoreResult(bool success) { + CHECK_EQ(STEP_STORE_TOKEN, enrollment_step_); + if (!success) { + ReportResult( + EnrollmentStatus::ForStatus(EnrollmentStatus::DM_TOKEN_STORE_FAILED)); + return; + } + + StartStoreRobotAuth(); +} + void EnrollmentHandlerChromeOS::HandleLockDeviceResult( chromeos::InstallAttributes::LockResult lock_result) { DCHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_); switch (lock_result) { case chromeos::InstallAttributes::LOCK_SUCCESS: - StartStoreRobotAuth(); + if (device_mode_ == DEVICE_MODE_ENTERPRISE_AD) { + StartStoreDMToken(); + } else { + StartStoreRobotAuth(); + } break; case chromeos::InstallAttributes::LOCK_NOT_READY: // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't @@ -459,6 +467,17 @@ } } +void EnrollmentHandlerChromeOS::StartStoreDMToken() { + DCHECK(device_mode_ == DEVICE_MODE_ENTERPRISE_AD); + SetStep(STEP_STORE_TOKEN); + dm_token_storage_ = base::MakeUnique<policy::DMTokenStorage>( + g_browser_process->local_state()); + dm_token_storage_->StoreDMToken( + client_->dm_token(), + base::Bind(&EnrollmentHandlerChromeOS::HandleDMTokenStoreResult, + weak_ptr_factory_.GetWeakPtr())); +} + void EnrollmentHandlerChromeOS::StartStoreRobotAuth() { SetStep(STEP_STORE_ROBOT_AUTH);
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h index 82232aa..6966101 100644 --- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h +++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -35,6 +35,7 @@ namespace policy { class DeviceCloudPolicyStoreChromeOS; +class DMTokenStorage; class ServerBackedStateKeysBroker; // Implements the logic that establishes enterprise enrollment for Chromium OS @@ -111,7 +112,7 @@ STEP_ROBOT_AUTH_FETCH = 6, // Fetching device API auth code. STEP_ROBOT_AUTH_REFRESH = 7, // Fetching device API refresh token. STEP_LOCK_DEVICE = 8, // Writing installation-time attributes. - STEP_STORE_TOKEN_AND_ID = 9, // Storing DM token and virtual device ID. + STEP_STORE_TOKEN = 9, // Encrypting and storing DM token. STEP_STORE_ROBOT_AUTH = 10, // Encrypting & writing robot refresh token. STEP_STORE_POLICY = 11, // Storing policy and API refresh token. For // AD, includes policy fetch via authpolicyd. @@ -145,6 +146,12 @@ void HandleLockDeviceResult( chromeos::InstallAttributes::LockResult lock_result); + // Initiates storing DM token. For Active Directory devices only. + void StartStoreDMToken(); + + // Called after StartStoreDMtoken() is done. + void HandleDMTokenStoreResult(bool success); + // Initiates storing of robot auth token. void StartStoreRobotAuth(); @@ -170,6 +177,7 @@ std::unique_ptr<CloudPolicyClient> client_; scoped_refptr<base::SequencedTaskRunner> background_task_runner_; std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; + std::unique_ptr<policy::DMTokenStorage> dm_token_storage_; EnrollmentConfig enrollment_config_; std::string auth_token_;
diff --git a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h index 9319869..bacd989f 100644 --- a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h +++ b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
@@ -43,6 +43,8 @@ ACTIVE_DIRECTORY_POLICY_FETCH_FAILED = 17, // Failed to fetch Active // Directory policy via // authpolicyd. + DM_TOKEN_STORE_FAILED = 18, // Failed to store DM token into the + // local state. }; // Helpers for constructing errors for relevant cases.
diff --git a/chrome/browser/conflicts/OWNERS b/chrome/browser/conflicts/OWNERS deleted file mode 100644 index 2ffdf656..0000000 --- a/chrome/browser/conflicts/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -chrisha@chromium.org -pmonette@chromium.org
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc deleted file mode 100644 index e68bd5e..0000000 --- a/chrome/browser/conflicts/module_database_win.cc +++ /dev/null
@@ -1,349 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/conflicts/module_database_win.h" - -#include <algorithm> -#include <tuple> - -#include "base/bind.h" - -namespace { - -// Document the assumptions made on the ProcessType enum in order to convert -// them to bits. -static_assert(content::PROCESS_TYPE_UNKNOWN == 1, - "assumes unknown process type has value 1"); -static_assert(content::PROCESS_TYPE_BROWSER == 2, - "assumes browser process type has value 2"); -constexpr uint32_t kFirstValidProcessType = content::PROCESS_TYPE_BROWSER; - -} // namespace - -ModuleDatabase::ModuleDatabase( - scoped_refptr<base::SequencedTaskRunner> task_runner) - : task_runner_(std::move(task_runner)), weak_ptr_factory_(this) {} - -ModuleDatabase::~ModuleDatabase() = default; - -void ModuleDatabase::OnProcessStarted(uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - CreateProcessInfo(process_id, creation_time, process_type); -} - -void ModuleDatabase::OnModuleLoad(uint32_t process_id, - uint64_t creation_time, - const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp, - uintptr_t module_load_address) { - // Messages can arrive from any thread (UI thread for calls over IPC, and - // anywhere at all for calls from ModuleWatcher), so bounce if necessary. - if (!task_runner_->RunsTasksOnCurrentThread()) { - task_runner_->PostTask( - FROM_HERE, base::Bind(&ModuleDatabase::OnModuleLoad, - weak_ptr_factory_.GetWeakPtr(), process_id, - creation_time, module_path, module_size, - module_time_date_stamp, module_load_address)); - return; - } - - // In theory this should always succeed. However, it is possible for a client - // to misbehave and send out-of-order messages. It is easy to be tolerant of - // this by simply not updating the process info in this case. It's not worth - // crashing if this data is slightly out of sync as this is purely - // informational. - auto* process_info = GetProcessInfo(process_id, creation_time); - if (!process_info) - return; - - auto* module_info = - FindOrCreateModuleInfo(module_path, module_size, module_time_date_stamp); - - // Update the list of process types that this module has been seen in. - module_info->second.process_types |= - ProcessTypeToBit(process_info->first.process_type); - - // Update the load address maps. - InsertLoadAddress(module_info->first.module_id, module_load_address, - &process_info->second.loaded_modules); - RemoveLoadAddressById(module_info->first.module_id, - &process_info->second.unloaded_modules); -} - -void ModuleDatabase::OnModuleUnload(uint32_t process_id, - uint64_t creation_time, - uintptr_t module_load_address) { - // Messages can arrive from any thread (UI thread for calls over IPC, and - // anywhere at all for calls from ModuleWatcher), so bounce if necessary. - if (!task_runner_->RunsTasksOnCurrentThread()) { - task_runner_->PostTask( - FROM_HERE, base::Bind(&ModuleDatabase::OnModuleUnload, - weak_ptr_factory_.GetWeakPtr(), process_id, - creation_time, module_load_address)); - return; - } - - // See the long-winded comment in OnModuleLoad about reasons why this can - // fail (but shouldn't normally). - auto* process_info = GetProcessInfo(process_id, creation_time); - if (!process_info) - return; - - // Find the module corresponding to this load address. This is O(1) in the - // common case of removing a recently removed module, but O(n) worst case. - // Thankfully, unload events occur far less often and n is quite small. - size_t i = FindLoadAddressIndexByAddress(module_load_address, - process_info->second.loaded_modules); - - // No such module found. This shouldn't happen either, unless messages are - // malformed or out of order. Gracefully fail in this case. - if (i == kInvalidIndex) - return; - - ModuleId module_id = process_info->second.loaded_modules[i].first; - - // Remove from the loaded module list and insert into the unloaded module - // list. - RemoveLoadAddressByIndex(i, &process_info->second.loaded_modules); - InsertLoadAddress(module_id, module_load_address, - &process_info->second.unloaded_modules); -} - -void ModuleDatabase::OnProcessEnded(uint32_t process_id, - uint64_t creation_time) { - // Messages can arrive from any thread (UI thread for calls over IPC, and - // anywhere at all for calls from ModuleWatcher), so bounce if necessary. - if (!task_runner_->RunsTasksOnCurrentThread()) { - task_runner_->PostTask( - FROM_HERE, - base::Bind(&ModuleDatabase::OnProcessEnded, - weak_ptr_factory_.GetWeakPtr(), process_id, creation_time)); - return; - } - - DeleteProcessInfo(process_id, creation_time); -} - -// static -uint32_t ModuleDatabase::ProcessTypeToBit(content::ProcessType process_type) { - uint32_t bit_index = - static_cast<uint32_t>(process_type) - kFirstValidProcessType; - DCHECK_GE(31u, bit_index); - uint32_t bit = (1 << bit_index); - return bit; -} - -// static -content::ProcessType ModuleDatabase::BitIndexToProcessType(uint32_t bit_index) { - DCHECK_GE(31u, bit_index); - return static_cast<content::ProcessType>(bit_index + kFirstValidProcessType); -} - -// static -size_t ModuleDatabase::FindLoadAddressIndexById( - ModuleId module_id, - const ModuleLoadAddresses& load_addresses) { - // Process elements in reverse order so that RemoveLoadAddressById can handle - // the more common case of removing the maximum element in O(1). - for (size_t i = load_addresses.size() - 1; i < load_addresses.size(); --i) { - if (load_addresses[i].first == module_id) - return i; - } - return kInvalidIndex; -} - -// static -size_t ModuleDatabase::FindLoadAddressIndexByAddress( - uintptr_t load_address, - const ModuleLoadAddresses& load_addresses) { - for (size_t i = 0; i < load_addresses.size(); ++i) { - if (load_addresses[i].second == load_address) - return i; - } - return kInvalidIndex; -} - -// static -void ModuleDatabase::InsertLoadAddress(ModuleId module_id, - uintptr_t load_address, - ModuleLoadAddresses* load_addresses) { - // A very small optimization: the largest module_id is always placed at the - // end of the array. This is the most common case, and allows O(1) - // determination that a |module_id| isn't present when it's bigger than the - // maximum already in the array. This keeps insertions to O(1) in the usual - // case. - if (load_addresses->empty() || module_id > load_addresses->back().first) { - load_addresses->emplace_back(module_id, load_address); - return; - } - - // If the module exists in the collection then update the load address and - // return. This should never really occur, unless the client is deliberately - // misbehaving or a race causes a reload event (at a different address) to be - // processed before the corresponding unload. This is very unlikely. - size_t i = FindLoadAddressIndexById(module_id, *load_addresses); - if (i != kInvalidIndex) { - (*load_addresses)[i].second = load_address; - return; - } - - // The module does not exist, and by definition is smaller in value than - // the largest module ID already present. Add it, ensuring that the largest - // module ID stays at the end. - load_addresses->emplace(--load_addresses->end(), module_id, load_address); -} - -// static -void ModuleDatabase::RemoveLoadAddressById( - ModuleId module_id, - ModuleLoadAddresses* load_addresses) { - if (load_addresses->empty()) - return; - - // This handles the special case of removing the max element in O(1), as - // FindLoadAddressIndexById processes the elements in reverse order. - size_t i = FindLoadAddressIndexById(module_id, *load_addresses); - RemoveLoadAddressByIndex(i, load_addresses); -} - -// static -void ModuleDatabase::RemoveLoadAddressByIndex( - size_t index, - ModuleLoadAddresses* load_addresses) { - DCHECK_LT(index, load_addresses->size()); - - // Special case: removing the last module (with maximum id). Need to find the - // new maximum element and ensure it goes to the end. - if (load_addresses->size() > 2 && index + 1 == load_addresses->size()) { - // Note that |index| == load_addresses->size() - 1, and is the last - // indexable element in the vector. - - // Find the index of the new maximum element. - ModuleId max_id = -1; // These start at zero. - size_t max_index = kInvalidIndex; - for (size_t i = 0; i < load_addresses->size() - 1; ++i) { - if ((*load_addresses)[i].first > max_id) { - max_id = (*load_addresses)[i].first; - max_index = i; - } - } - - // Remove the last (max) element. - load_addresses->resize(index); - - // If the new max element isn't in the last position, then swap it so it is. - size_t last_index = load_addresses->size() - 1; - if (max_index != last_index) - std::swap((*load_addresses)[max_index], (*load_addresses)[last_index]); - - return; - } - - // If the element to be removed is second last then a single copy is - // sufficient. - if (index + 2 == load_addresses->size()) { - (*load_addresses)[index] = (*load_addresses)[index + 1]; - } else { - // In the general case two copies are necessary. - int max_index = load_addresses->size() - 1; - (*load_addresses)[index] = (*load_addresses)[max_index - 1]; - (*load_addresses)[max_index - 1] = (*load_addresses)[max_index]; - } - - // Remove the last element, which is now duplicated. - load_addresses->resize(load_addresses->size() - 1); -} - -ModuleDatabase::ModuleInfo* ModuleDatabase::FindOrCreateModuleInfo( - const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp) { - auto result = modules_.emplace( - std::piecewise_construct, - std::forward_as_tuple(ModuleInfoKey( - module_path, module_size, module_time_date_stamp, modules_.size())), - std::forward_as_tuple(ModuleInfoData())); - return &(*result.first); -} - -ModuleDatabase::ProcessInfo* ModuleDatabase::GetProcessInfo( - uint32_t process_id, - uint64_t creation_time) { - ProcessInfoKey key(process_id, creation_time, content::PROCESS_TYPE_UNKNOWN); - auto it = processes_.find(key); - if (it == processes_.end()) - return nullptr; - return &(*it); -} - -void ModuleDatabase::CreateProcessInfo(uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type) { - processes_.emplace(std::piecewise_construct, - std::forward_as_tuple(ProcessInfoKey( - process_id, creation_time, process_type)), - std::forward_as_tuple(ProcessInfoData())); -} - -void ModuleDatabase::DeleteProcessInfo(uint32_t process_id, - uint64_t creation_time) { - ProcessInfoKey key(process_id, creation_time, content::PROCESS_TYPE_UNKNOWN); - processes_.erase(key); -} - -// ModuleDatabase::ModuleInfoKey ----------------------------------------------- - -ModuleDatabase::ModuleInfoKey::ModuleInfoKey(const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp, - uint32_t module_id) - : module_path(module_path), - module_size(module_size), - module_time_date_stamp(module_time_date_stamp), - module_id(module_id) {} - -bool ModuleDatabase::ModuleInfoKey::operator<(const ModuleInfoKey& mik) const { - // The key consists of the triplet of - // (module_path, module_size, module_time_date_stamp). - // Use the std::tuple lexicographic comparison operator. - return std::make_tuple(module_path, module_size, module_time_date_stamp) < - std::make_tuple(mik.module_path, mik.module_size, - mik.module_time_date_stamp); -} - -// ModuleDatabase::ModuleInfoData ---------------------------------------------- - -ModuleDatabase::ModuleInfoData::ModuleInfoData() : process_types(0) {} - -// ModuleDatabase::ProcessInfoKey ---------------------------------------------- - -ModuleDatabase::ProcessInfoKey::ProcessInfoKey( - uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type) - : process_id(process_id), - creation_time(creation_time), - process_type(process_type) {} - -ModuleDatabase::ProcessInfoKey::~ProcessInfoKey() = default; - -bool ModuleDatabase::ProcessInfoKey::operator<( - const ProcessInfoKey& pik) const { - // The key consists of the pair of (process_id, creation_time). - // Use the std::tuple lexicographic comparison operator. - return std::make_tuple(process_id, creation_time) < - std::make_tuple(pik.process_id, pik.creation_time); -} - -// ModuleDatabase::ProcessInfoData --------------------------------------------- - -ModuleDatabase::ProcessInfoData::ProcessInfoData() = default; - -ModuleDatabase::ProcessInfoData::ProcessInfoData(const ProcessInfoData& other) = - default; - -ModuleDatabase::ProcessInfoData::~ProcessInfoData() = default;
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h deleted file mode 100644 index 8172082..0000000 --- a/chrome/browser/conflicts/module_database_win.h +++ /dev/null
@@ -1,243 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CONFLICTS_MODULE_DATABASE_WIN_H_ -#define CHROME_BROWSER_CONFLICTS_MODULE_DATABASE_WIN_H_ - -#include <map> -#include <utility> -#include <vector> - -#include "base/files/file_path.h" -#include "base/memory/weak_ptr.h" -#include "base/sequenced_task_runner.h" -#include "content/public/common/process_type.h" - -// A class that keeps track of all modules loaded across Chrome processes. -// Drives the chrome://conflicts UI. -class ModuleDatabase { - public: - // A ModuleDatabase is by default bound to a provided sequenced task runner. - // All calls must be made in the context of this task runner, unless - // otherwise noted. For calls from other contexts this task runner is used to - // bounce the call when appropriate. - explicit ModuleDatabase(scoped_refptr<base::SequencedTaskRunner> task_runner); - ~ModuleDatabase(); - - // Indicates that process with the given type has started. This must be called - // before any calls to OnModuleEvent or OnModuleUnload. Must be called in the - // same sequence as |task_runner_|. - void OnProcessStarted(uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type); - - // Indicates that a module has been loaded. The data passed to this function - // is taken as gospel, so if it originates from a remote process it should be - // independently validated first. (In practice, see ModuleEventSinkImpl for - // details of where this happens.) - void OnModuleLoad(uint32_t process_id, - uint64_t creation_time, - const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp, - uintptr_t module_load_address); - - // Indicates that the module at the given |load_address| in the specified - // process is being unloaded. This need not be trusted data, as it will be - // validated by the ModuleDatabase directly. - void OnModuleUnload(uint32_t process_id, - uint64_t creation_time, - uintptr_t module_load_address); - - // Indicates that the given process has ended. This can be called from any - // thread and will be bounced to the |task_runner_|. In practice it will be - // invoked from the UI thread as the Mojo channel is torn down. - void OnProcessEnded(uint32_t process_id, uint64_t creation_time); - - // TODO(chrisha): Module analysis code, and various accessors for use by - // chrome://conflicts. - - private: - friend class TestModuleDatabase; - friend class ModuleDatabaseTest; - friend class ModuleEventSinkImplTest; - - // Used by the FindLoadAddress* functions to indicate a load address has not - // been found. - static constexpr size_t kInvalidIndex = ~0u; - - // Used as a unique identifier for a module in a ModuleSet. - using ModuleId = int; - - // Structures for maintaining information about modules. - struct ModuleInfoKey; - struct ModuleInfoData; - using ModuleMap = std::map<ModuleInfoKey, ModuleInfoData>; - using ModuleInfo = ModuleMap::value_type; - - // Used for maintaing a list of modules loaded in a process. Maps module IDs - // to load addresses. - using ModuleLoadAddresses = std::vector<std::pair<ModuleId, uintptr_t>>; - - // Structures for maintaining information about running processes. - struct ProcessInfoKey; - struct ProcessInfoData; - using ProcessMap = std::map<ProcessInfoKey, ProcessInfoData>; - using ProcessInfo = ProcessMap::value_type; - - // Converts a valid |process_type| to a bit for use in a bitmask of process - // values. Exposed in the header for testing. - static uint32_t ProcessTypeToBit(content::ProcessType process_type); - - // Converts a |bit_index| (which maps to the bit 1 << bit_index) to the - // corresponding process type. Exposed in the header for testing. - static content::ProcessType BitIndexToProcessType(uint32_t bit_index); - - // Performs a linear scan to find the index of a |module_id| or |load_address| - // in a collection of modules. Returns kInvalidIndex if the index is not - // found. - static size_t FindLoadAddressIndexById( - ModuleId module_id, - const ModuleLoadAddresses& load_addresses); - static size_t FindLoadAddressIndexByAddress( - uintptr_t load_address, - const ModuleLoadAddresses& load_addresses); - - // Inserts a module into a ModuleLoadAddress object. - static void InsertLoadAddress(ModuleId module_id, - uintptr_t load_address, - ModuleLoadAddresses* load_addresses); - - // Removes a module from a ModuleLoadAddress object, either by the - // |module_id| or the |index| in the collection. - static void RemoveLoadAddressById(ModuleId module_id, - ModuleLoadAddresses* load_addresses); - static void RemoveLoadAddressByIndex(size_t index, - ModuleLoadAddresses* load_addresses); - - // Finds or creates a mutable ModuleInfo entry. - ModuleInfo* FindOrCreateModuleInfo(const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp); - - // Finds a process info entry. Returns nullptr if none is found. - ProcessInfo* GetProcessInfo(uint32_t process_id, uint64_t creation_time); - - // Creates a process info entry. - void CreateProcessInfo(uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type); - - // Deletes a process info entry. - void DeleteProcessInfo(uint32_t process_id, uint64_t creation_time); - - // The task runner to which this object is bound. - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - // A map of all known modules. - ModuleMap modules_; - - // A map of all known running processes, and modules loaded/unloaded in - // them. - ProcessMap processes_; - - // Weak pointer factory for this object. This is used when bouncing - // incoming events to |task_runner_|. - base::WeakPtrFactory<ModuleDatabase> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ModuleDatabase); -}; - -// Maintains information about a module. Modules are permanent once added to -// the ModuleSet, so this structure grows monotonically. In practice this is -// not an issue as the modules themselves are vastly bigger than the minor -// amount of metadata tracked here. - -// This is the constant portion of the module information, and acts as the key -// in a std::map. -struct ModuleDatabase::ModuleInfoKey { - ModuleInfoKey(const base::FilePath& module_path, - uint32_t module_size, - uint32_t module_time_date_stamp, - uint32_t module_id); - - // Less-than operator allowing this object to be used in std::map. - bool operator<(const ModuleInfoKey& mi) const; - - // Full path to the module on disk. Part of the key for a ModuleInfo. - base::FilePath module_path; - - // The module size. Part of the key for a ModuleInfo. This is taken from - // SizeOfImage from the module's IMAGE_OPTIONAL_HEADER. - uint32_t module_size; - - // The module time date stamp. Part of the key for a ModuleInfo. Taken from - // TimeDateStamp from the module's IMAGE_FILE_HEADER. - uint32_t module_time_date_stamp; - - // The ID of this module. This is a strictly incrementing value, and is used - // to tie a module to the list of running processes in which it is found. - // It is not part of the key for the module, but it is immutable. This is - // simply the index of the module in the insertion order. - ModuleId module_id; -}; - -// This is the mutable portion of the module information, and is the storage -// type in a std::map. -struct ModuleDatabase::ModuleInfoData { - ModuleInfoData(); - - // Set of all process types in which this module has been seen (may not be - // currently present in a process of that type). This is a conversion of - // ProcessType enumeration to a bitfield. See "ProcessTypeToBit" and - // "BitIndexToProcessType" for details. - uint32_t process_types; -}; - -// Information about a running process. This ties modules in a ModuleSet to -// processes in which they are (or have been) loaded. - -// This is the constant portion of the process information, and acts as the key -// in a std::map. -struct ModuleDatabase::ProcessInfoKey { - ProcessInfoKey(uint32_t process_id, - uint64_t creation_time, - content::ProcessType process_type); - ~ProcessInfoKey(); - - // Less-than operator allowing this object to be used in std::map. - bool operator<(const ProcessInfoKey& pi) const; - - // The process ID. - uint32_t process_id; - - // The process creation time. A raw FILETIME value with full precision. - // Combined with |process_id| this uniquely identifies a process on a Windows - // system. - uint64_t creation_time; - - // The type of the process. - content::ProcessType process_type; -}; - -// This is the mutable portion of the process information, and is the storage -// type in a std::map. -struct ModuleDatabase::ProcessInfoData { - ProcessInfoData(); - ProcessInfoData(const ProcessInfoData& other); - ~ProcessInfoData(); - - // The sets of modules that are loaded/unloaded in this process, by ID. This - // is typically a small list so a linear cost is okay to pay for - // lookup/deletion (storage is backed by a vector). - // - // These are modified by the various static *LoadAddress* helper functions in - // ModuleDatabase. The vector maintains the invariant the element with maximum - // module ID is always last. This ensures that the usual operation of loading - // a module is O(1). - ModuleLoadAddresses loaded_modules; - ModuleLoadAddresses unloaded_modules; -}; - -#endif // CHROME_BROWSER_CONFLICTS_MODULE_DATABASE_WIN_H_
diff --git a/chrome/browser/conflicts/module_database_win_unittest.cc b/chrome/browser/conflicts/module_database_win_unittest.cc deleted file mode 100644 index a5c3c17..0000000 --- a/chrome/browser/conflicts/module_database_win_unittest.cc +++ /dev/null
@@ -1,529 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/conflicts/module_database_win.h" - -#include <algorithm> -#include <memory> -#include <vector> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// A simple mechanism for running a single task on a separate thread. -class SingleTaskRunner : public base::SimpleThread { - public: - explicit SingleTaskRunner(base::Closure task) - : base::SimpleThread("SingleTaskRunner"), task_(std::move(task)) {} - - // Runs the provided task and exits. - void Run() override { task_.Run(); } - - private: - base::Closure task_; - DISALLOW_COPY_AND_ASSIGN(SingleTaskRunner); -}; - -// Launches a thread and runs a single task on it. -void RunTask(base::Closure task) { - SingleTaskRunner task_runner(std::move(task)); - task_runner.Start(); - task_runner.Join(); -} - -constexpr uint32_t kPid1 = 1234u; -constexpr uint32_t kPid2 = 2345u; - -constexpr uint64_t kCreateTime1 = 1234u; -constexpr uint64_t kCreateTime2 = 2345u; - -constexpr wchar_t kDll1[] = L"dummy.dll"; -constexpr wchar_t kDll2[] = L"foo.dll"; - -constexpr size_t kSize1 = 100 * 4096; -constexpr size_t kSize2 = 20 * 4096; - -constexpr uint32_t kTime1 = 0xDEADBEEF; -constexpr uint32_t kTime2 = 0xBAADF00D; - -constexpr uintptr_t kGoodAddress1 = 0x04000000u; -constexpr uintptr_t kGoodAddress2 = 0x05000000u; - -} // namespace - -class TestModuleDatabase : ModuleDatabase { - public: - // Types. - using ModuleDatabase::ModuleId; - using ModuleDatabase::ModuleLoadAddresses; - - // Constants. - using ModuleDatabase::kInvalidIndex; - - // Functions. - using ModuleDatabase::FindLoadAddressIndexById; - using ModuleDatabase::FindLoadAddressIndexByAddress; - using ModuleDatabase::InsertLoadAddress; - using ModuleDatabase::RemoveLoadAddressById; - using ModuleDatabase::RemoveLoadAddressByIndex; -}; - -class ModuleDatabaseTest : public testing::Test { - protected: - ModuleDatabaseTest() - : dll1_(kDll1), - dll2_(kDll2), - message_loop_(base::MakeUnique<base::MessageLoop>()), - module_database_( - base::MakeUnique<ModuleDatabase>(message_loop_->task_runner())) {} - - void RunLoopUntilIdle() { base::RunLoop().RunUntilIdle(); } - - const ModuleDatabase::ModuleMap& modules() { - return module_database_->modules_; - } - - const ModuleDatabase::ProcessMap& processes() { - return module_database_->processes_; - } - - static uint32_t ProcessTypeToBit(content::ProcessType process_type) { - return ModuleDatabase::ProcessTypeToBit(process_type); - } - - // Counts the occurrences of the given |module_id| in the given collection of - // |load_addresses|. - static size_t ModuleIdCount( - ModuleDatabase::ModuleId module_id, - const ModuleDatabase::ModuleLoadAddresses& load_addresses) { - return std::count_if( - load_addresses.begin(), load_addresses.end(), - [module_id](const auto& x) { return module_id == x.first; }); - } - - protected: - const base::FilePath dll1_; - const base::FilePath dll2_; - - std::unique_ptr<base::MessageLoop> message_loop_; - std::unique_ptr<ModuleDatabase> module_database_; - - private: - DISALLOW_COPY_AND_ASSIGN(ModuleDatabaseTest); -}; - -TEST_F(ModuleDatabaseTest, LoadAddressVectorOperations) { - using TMD = TestModuleDatabase; - TestModuleDatabase::ModuleLoadAddresses la; - - // Finds should fail in an empty collection. - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0, la)); - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0x04000000, la)); - - // A first insert should work. Don't start with ModuleId 0 so that later - // inserts can insert that module. - TMD::InsertLoadAddress(10, 0x04000000, &la); - EXPECT_EQ(1u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - - // Finds should work. - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0, la)); - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0x03000000, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexById(10, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexByAddress(0x04000000, la)); - - // A second insert should work. This is the new max so should be at the end - // of the collection. - TMD::InsertLoadAddress(12, 0x06000000, &la); - EXPECT_EQ(2u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(12, la[1].first); - EXPECT_EQ(0x06000000u, la[1].second); - - // Finds should work. - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0, la)); - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0x03000000, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexById(10, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexByAddress(0x04000000, la)); - EXPECT_EQ(1u, TMD::FindLoadAddressIndexById(12, la)); - EXPECT_EQ(1u, TMD::FindLoadAddressIndexByAddress(0x06000000, la)); - - // Another insert should work. This is not the new max, so a swap should - // happen to keep the maximum element at the end of the collection. - TMD::InsertLoadAddress(11, 0x05000000, &la); - EXPECT_EQ(3u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x05000000u, la[1].second); - EXPECT_EQ(12, la[2].first); - EXPECT_EQ(0x06000000u, la[2].second); - - // An insert of an existing module should work, but simply overwrite the - // load address. - TMD::InsertLoadAddress(11, 0x0F000000, &la); - EXPECT_EQ(3u, la.size()); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x0F000000u, la[1].second); - TMD::InsertLoadAddress(11, 0x05000000, &la); - EXPECT_EQ(3u, la.size()); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x05000000u, la[1].second); - - // Finds should work. - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0, la)); - EXPECT_EQ(TMD::kInvalidIndex, TMD::FindLoadAddressIndexById(0x03000000, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexById(10, la)); - EXPECT_EQ(0u, TMD::FindLoadAddressIndexByAddress(0x04000000, la)); - EXPECT_EQ(1u, TMD::FindLoadAddressIndexById(11, la)); - EXPECT_EQ(1u, TMD::FindLoadAddressIndexByAddress(0x05000000, la)); - EXPECT_EQ(2u, TMD::FindLoadAddressIndexById(12, la)); - EXPECT_EQ(2u, TMD::FindLoadAddressIndexByAddress(0x06000000, la)); - - // Do some inserts of lower modules IDs. This ensures that we'll have some - // higher module IDs in the vector before some lower modules IDs, for testing - // the deletion logic. - TMD::InsertLoadAddress(3, 0x07000000, &la); - TMD::InsertLoadAddress(4, 0x08000000, &la); - TMD::InsertLoadAddress(5, 0x09000000, &la); - EXPECT_EQ(6u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x05000000u, la[1].second); - EXPECT_EQ(3, la[2].first); - EXPECT_EQ(0x07000000u, la[2].second); - EXPECT_EQ(4, la[3].first); - EXPECT_EQ(0x08000000u, la[3].second); - EXPECT_EQ(5, la[4].first); - EXPECT_EQ(0x09000000u, la[4].second); - EXPECT_EQ(12, la[5].first); - EXPECT_EQ(0x06000000u, la[5].second); - - // Remove an element that isn't in the second last position. The second last - // element should be swapped into its position, and the last element moved - // to the second last place. - TMD::RemoveLoadAddressByIndex(2, &la); - EXPECT_EQ(5u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x05000000u, la[1].second); - EXPECT_EQ(5, la[2].first); - EXPECT_EQ(0x09000000u, la[2].second); - EXPECT_EQ(4, la[3].first); - EXPECT_EQ(0x08000000u, la[3].second); - EXPECT_EQ(12, la[4].first); - EXPECT_EQ(0x06000000u, la[4].second); - - // Remove the second last element. Only the last element should move. - TMD::RemoveLoadAddressByIndex(3, &la); - EXPECT_EQ(4u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(11, la[1].first); - EXPECT_EQ(0x05000000u, la[1].second); - EXPECT_EQ(5, la[2].first); - EXPECT_EQ(0x09000000u, la[2].second); - EXPECT_EQ(12, la[3].first); - EXPECT_EQ(0x06000000u, la[3].second); - - // Remove the last element. The new maximum should be found moved to the - // end. - TMD::RemoveLoadAddressByIndex(3, &la); - EXPECT_EQ(3u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - EXPECT_EQ(5, la[1].first); - EXPECT_EQ(0x09000000u, la[1].second); - EXPECT_EQ(11, la[2].first); - EXPECT_EQ(0x05000000u, la[2].second); - - // Remove the last element by ModuleId. The remaining modules should be - // swapped. - TMD::RemoveLoadAddressById(11, &la); - EXPECT_EQ(2u, la.size()); - EXPECT_EQ(5, la[0].first); - EXPECT_EQ(0x09000000u, la[0].second); - EXPECT_EQ(10, la[1].first); - EXPECT_EQ(0x04000000u, la[1].second); - - // Remove the first element by ModuleId. - TMD::RemoveLoadAddressById(5, &la); - EXPECT_EQ(1u, la.size()); - EXPECT_EQ(10, la[0].first); - EXPECT_EQ(0x04000000u, la[0].second); - - // Remove the only remaining element. - TMD::RemoveLoadAddressByIndex(0, &la); - EXPECT_TRUE(la.empty()); -} - -TEST_F(ModuleDatabaseTest, LoadAddressVectorStressTest) { - using TMD = TestModuleDatabase; - TestModuleDatabase::ModuleLoadAddresses la; - - for (size_t n = 1; n < 200; ++n) { - // Will keep track of which elements have been inserted. - std::vector<bool> inserted(n); - size_t inserted_count = 0; - - // Generate a shuffled list of IDs. This will be the insertion order. - // More insertions than elements will occur so that rewrites occur., - std::vector<TMD::ModuleId> ids(11 * n / 10); - for (size_t i = 0; i < 11 * n / 10; ++i) - ids[i] = i % n; - std::random_shuffle(ids.begin(), ids.end()); - - // Do the insertions. - for (auto id : ids) { - if (!inserted[id]) { - inserted[id] = true; - ++inserted_count; - } - - // Generate a load address. The load address bakes in the index so that - // searching by load address is easy. - uintptr_t load_address = static_cast<uintptr_t>(id) << 16; - - // Do the insertion. - TMD::InsertLoadAddress(id, load_address, &la); - EXPECT_EQ(inserted_count, la.size()); - } - - // Validate that every element is there, via both search mechanisms. - for (size_t id = 0; id < n; ++id) { - uintptr_t load_address = static_cast<uintptr_t>(id) << 16; - size_t index1 = TMD::FindLoadAddressIndexById(id, la); - size_t index2 = TMD::FindLoadAddressIndexByAddress(load_address, la); - EXPECT_NE(TMD::kInvalidIndex, index1); - EXPECT_EQ(index1, index2); - } - - // Generate the deletion order. - ids.resize(n); - for (size_t i = 0; i < ids.size(); ++i) - ids[i] = i; - std::random_shuffle(ids.begin(), ids.end()); - - // Do the deletions. - for (auto id : ids) { - --inserted_count; - TMD::RemoveLoadAddressById(id, &la); - EXPECT_EQ(inserted_count, la.size()); - } - } -} - -TEST_F(ModuleDatabaseTest, TasksAreBounced) { - // Run a task on the current thread. This should not be bounced, so no - // task should be scheduled on the task runner. - module_database_->OnProcessStarted(kPid1, kCreateTime1, - content::PROCESS_TYPE_BROWSER); - EXPECT_TRUE(message_loop_->IsIdleForTesting()); - module_database_->OnModuleLoad(kPid1, kCreateTime1, dll1_, kSize1, kTime1, - kGoodAddress1); - EXPECT_TRUE(message_loop_->IsIdleForTesting()); - module_database_->OnProcessEnded(kPid1, kCreateTime1); - EXPECT_TRUE(message_loop_->IsIdleForTesting()); - - // Indicate another process start on this thread. This call can't be - // bounced. - module_database_->OnProcessStarted(kPid2, kCreateTime2, - content::PROCESS_TYPE_BROWSER); - - // Run similar tasks on another thread. These should be bounced. - RunTask(base::Bind(&ModuleDatabase::OnModuleLoad, - base::Unretained(module_database_.get()), kPid2, - kCreateTime2, dll1_, kSize1, kTime1, kGoodAddress1)); - EXPECT_FALSE(message_loop_->IsIdleForTesting()); - RunLoopUntilIdle(); - - RunTask(base::Bind(&ModuleDatabase::OnProcessEnded, - base::Unretained(module_database_.get()), kPid2, - kCreateTime2)); - EXPECT_FALSE(message_loop_->IsIdleForTesting()); - RunLoopUntilIdle(); -} - -TEST_F(ModuleDatabaseTest, EventsWithoutProcessIgnore) { - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(0u, processes().size()); - - module_database_->OnModuleLoad(kPid1, kCreateTime1, dll1_, kSize1, kTime1, - kGoodAddress1); - - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(0u, processes().size()); -} - -TEST_F(ModuleDatabaseTest, OrphanedUnloadIgnored) { - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(0u, processes().size()); - - // Start a process. - module_database_->OnProcessStarted(kPid1, kCreateTime1, - content::PROCESS_TYPE_BROWSER); - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(1u, processes().size()); - auto p1 = processes().begin(); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(0u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); - - // Indicate a module unload. This should do nothing because there's no - // corresponding module. - module_database_->OnModuleUnload(kPid1, kCreateTime1, kGoodAddress1); - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(1u, processes().size()); - EXPECT_EQ(0u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); -} - -TEST_F(ModuleDatabaseTest, DatabaseIsConsistent) { - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(0u, processes().size()); - - // Start a process. - module_database_->OnProcessStarted(kPid1, kCreateTime1, - content::PROCESS_TYPE_BROWSER); - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(1u, processes().size()); - auto p1 = processes().begin(); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(0u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); - - // Load a module. - module_database_->OnModuleLoad(kPid1, kCreateTime1, dll1_, kSize1, kTime1, - kGoodAddress1); - EXPECT_EQ(1u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // Ensure that the process and module sets are up to date. - auto m1 = modules().begin(); - EXPECT_EQ(dll1_, m1->first.module_path); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m1->second.process_types); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(1u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); - EXPECT_EQ(1u, ModuleIdCount(m1->first.module_id, p1->second.loaded_modules)); - - // Provide a redundant load message for that module. - module_database_->OnModuleLoad(kPid1, kCreateTime1, dll1_, kSize1, kTime1, - kGoodAddress1); - EXPECT_EQ(1u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // Ensure that the process and module sets haven't changed. - EXPECT_EQ(dll1_, m1->first.module_path); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m1->second.process_types); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(1u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); - EXPECT_EQ(1u, ModuleIdCount(m1->first.module_id, p1->second.loaded_modules)); - - // Load a second module into the process. - module_database_->OnModuleLoad(kPid1, kCreateTime1, dll2_, kSize2, kTime2, - kGoodAddress2); - EXPECT_EQ(2u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // Ensure that the process and module sets are up to date. - auto m2 = modules().rbegin(); - EXPECT_EQ(dll2_, m2->first.module_path); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m2->second.process_types); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(2u, p1->second.loaded_modules.size()); - EXPECT_EQ(0u, p1->second.unloaded_modules.size()); - EXPECT_EQ(1u, ModuleIdCount(m1->first.module_id, p1->second.loaded_modules)); - EXPECT_EQ(1u, ModuleIdCount(m2->first.module_id, p1->second.loaded_modules)); - - // Unload the second module. - module_database_->OnModuleUnload(kPid1, kCreateTime1, kGoodAddress2); - EXPECT_EQ(2u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // Ensure that the process and module sets are up to date. - EXPECT_EQ(dll2_, m2->first.module_path); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m2->second.process_types); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_BROWSER, p1->first.process_type); - EXPECT_EQ(1u, p1->second.loaded_modules.size()); - EXPECT_EQ(1u, p1->second.unloaded_modules.size()); - EXPECT_EQ(1u, ModuleIdCount(m1->first.module_id, p1->second.loaded_modules)); - EXPECT_EQ(1u, - ModuleIdCount(m2->first.module_id, p1->second.unloaded_modules)); - - // Start a process. - module_database_->OnProcessStarted(kPid2, kCreateTime2, - content::PROCESS_TYPE_RENDERER); - EXPECT_EQ(2u, modules().size()); - EXPECT_EQ(2u, processes().size()); - auto p2 = processes().rbegin(); - EXPECT_EQ(kPid2, p2->first.process_id); - EXPECT_EQ(kCreateTime2, p2->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_RENDERER, p2->first.process_type); - EXPECT_EQ(0u, p2->second.loaded_modules.size()); - EXPECT_EQ(0u, p2->second.unloaded_modules.size()); - - // Load the dummy.dll in the second process as well. - module_database_->OnModuleLoad(kPid2, kCreateTime2, dll1_, kSize1, kTime1, - kGoodAddress1); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER) | - ProcessTypeToBit(content::PROCESS_TYPE_RENDERER), - m1->second.process_types); - EXPECT_EQ(kPid2, p2->first.process_id); - EXPECT_EQ(kCreateTime2, p2->first.creation_time); - EXPECT_EQ(content::PROCESS_TYPE_RENDERER, p2->first.process_type); - EXPECT_EQ(1u, p2->second.loaded_modules.size()); - EXPECT_EQ(0u, p2->second.unloaded_modules.size()); - EXPECT_EQ(1u, ModuleIdCount(m1->first.module_id, p2->second.loaded_modules)); - - // End the second process without an explicit unload. This invalidates |p2|. - module_database_->OnProcessEnded(kPid2, kCreateTime2); - EXPECT_EQ(2u, modules().size()); - EXPECT_EQ(1u, processes().size()); - EXPECT_EQ(kPid1, p1->first.process_id); - EXPECT_EQ(kCreateTime1, p1->first.creation_time); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER) | - ProcessTypeToBit(content::PROCESS_TYPE_RENDERER), - m1->second.process_types); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m2->second.process_types); - - // End the first process without an explicit unload. This invalidates |p1|. - module_database_->OnProcessEnded(kPid1, kCreateTime1); - EXPECT_EQ(2u, modules().size()); - EXPECT_EQ(0u, processes().size()); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER) | - ProcessTypeToBit(content::PROCESS_TYPE_RENDERER), - m1->second.process_types); - EXPECT_EQ(ProcessTypeToBit(content::PROCESS_TYPE_BROWSER), - m2->second.process_types); -}
diff --git a/chrome/browser/conflicts/module_event_sink_impl_win.cc b/chrome/browser/conflicts/module_event_sink_impl_win.cc deleted file mode 100644 index 428b382..0000000 --- a/chrome/browser/conflicts/module_event_sink_impl_win.cc +++ /dev/null
@@ -1,210 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/conflicts/module_event_sink_impl_win.h" - -#include <windows.h> -#include <psapi.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string_piece.h" -#include "chrome/browser/conflicts/module_database_win.h" -#include "chrome/common/conflicts/module_watcher_win.h" -#include "content/public/browser/browser_thread.h" -#include "mojo/public/cpp/bindings/strong_binding.h" - -namespace { - -// Gets the process creation time associated with the given process. -bool GetProcessCreationTime(base::ProcessHandle process, - uint64_t* creation_time) { - FILETIME creation_ft = {}; - FILETIME exit_ft = {}; - FILETIME kernel_ft = {}; - FILETIME user_ft = {}; - if (!::GetProcessTimes(process, &creation_ft, &exit_ft, &kernel_ft, - &user_ft)) { - return false; - } - *creation_time = (static_cast<uint64_t>(creation_ft.dwHighDateTime) << 32) | - static_cast<uint64_t>(creation_ft.dwLowDateTime); - return true; -} - -// Gets the path of the module in the provided remote process. Returns true on -// success, false otherwise. -bool GetModulePath(base::ProcessHandle process, - HMODULE module, - base::FilePath* path) { - std::vector<wchar_t> temp_path(MAX_PATH); - size_t length = 0; - while (true) { - length = ::GetModuleFileNameEx(process, module, temp_path.data(), - temp_path.size()); - if (length == 0) - return false; - if (length < temp_path.size()) - break; - // The entire buffer was consumed, so grow it to ensure the result wasn't - // actually truncated. - temp_path.resize(2 * temp_path.size()); - } - - *path = base::FilePath(base::StringPiece16(temp_path.data(), length)); - return true; -} - -// Gets the size of a module in a remote process. Returns true on success, false -// otherwise. -bool GetModuleSize(base::ProcessHandle process, - HMODULE module, - uint32_t* size) { - MODULEINFO info = {}; - if (!::GetModuleInformation(process, module, &info, sizeof(info))) - return false; - *size = info.SizeOfImage; - return true; -} - -// Reads the typed data from a remote process. Returns true on success, false -// otherwise. -template <typename T> -bool ReadRemoteData(base::ProcessHandle process, uint64_t address, T* data) { - const void* typed_address = - reinterpret_cast<const void*>(static_cast<uintptr_t>(address)); - SIZE_T bytes_read = 0; - if (!::ReadProcessMemory(process, typed_address, &data, sizeof(data), - &bytes_read)) { - return false; - } - if (bytes_read != sizeof(data)) - return false; - return true; -} - -// Reads the time date stamp from the module loaded in the provided remote -// |process| at the provided remote |load_address|. -bool GetModuleTimeDateStamp(base::ProcessHandle process, - uint64_t load_address, - uint32_t* time_date_stamp) { - uint64_t address = load_address + offsetof(IMAGE_DOS_HEADER, e_lfanew); - LONG e_lfanew = 0; - if (!ReadRemoteData(process, address, &e_lfanew)) - return false; - - address = load_address + e_lfanew + offsetof(IMAGE_NT_HEADERS, FileHeader) + - offsetof(IMAGE_FILE_HEADER, TimeDateStamp); - DWORD temp = 0; - if (!ReadRemoteData(process, address, &temp)) - return false; - - *time_date_stamp = temp; - return true; -} - -} // namespace - -ModuleEventSinkImpl::ModuleEventSinkImpl(base::ProcessHandle process, - content::ProcessType process_type, - ModuleDatabase* module_database) - : process_(process), - module_database_(module_database), - process_id_(0), - creation_time_(0), - in_error_(false) { - // Failing to get basic process information means this channel should not - // continue to forward data, thus it is marked as being in error. - process_id_ = ::GetProcessId(process_); - if (!GetProcessCreationTime(process_, &creation_time_)) { - in_error_ = true; - return; - } - module_database->OnProcessStarted(process_id_, creation_time_, process_type); -} - -ModuleEventSinkImpl::~ModuleEventSinkImpl() = default; - -// static -void ModuleEventSinkImpl::Create(base::ProcessHandle process, - content::ProcessType process_type, - ModuleDatabase* module_database, - mojom::ModuleEventSinkRequest request) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - auto module_event_sink_impl = base::MakeUnique<ModuleEventSinkImpl>( - process, process_type, module_database); - base::Closure error_handler = base::Bind( - &ModuleDatabase::OnProcessEnded, base::Unretained(module_database), - module_event_sink_impl->process_id_, - module_event_sink_impl->creation_time_); - auto binding = mojo::MakeStrongBinding(std::move(module_event_sink_impl), - std::move(request)); - binding->set_connection_error_handler(error_handler); -} - -void ModuleEventSinkImpl::OnModuleEvent(mojom::ModuleEventType event_type, - uint64_t load_address) { - if (in_error_) - return; - - // Mojo takes care of validating |event_type|, so only |load_address| needs to - // be checked. Load addresses must be aligned with the allocation granularity - // which is at least 64KB on any supported Windows OS. - if (load_address == 0 || load_address % (64 * 1024) != 0) - return; - - switch (event_type) { - case mojom::ModuleEventType::MODULE_ALREADY_LOADED: - case mojom::ModuleEventType::MODULE_LOADED: - return OnModuleLoad(load_address); - - case mojom::ModuleEventType::MODULE_UNLOADED: - return OnModuleUnload(load_address); - } -} - -void ModuleEventSinkImpl::OnModuleLoad(uint64_t load_address) { - if (in_error_) - return; - - // The |load_address| is a unique key to a module in a remote process. If - // there is a valid module there then the following queries should all pass. - // If any of them fail then the load event is silently swallowed. The entire - // channel is not marked as being in an error mode, as later events may be - // well formed. - - // Convert the |load_address| to a module handle. - HMODULE module = - reinterpret_cast<HMODULE>(static_cast<uintptr_t>(load_address)); - - // Look up the various pieces of module metadata in the remote process. - - base::FilePath module_path; - if (!GetModulePath(process_, module, &module_path)) - return; - - uint32_t module_size = 0; - if (!GetModuleSize(process_, module, &module_size)) - return; - - uint32_t module_time_date_stamp = 0; - if (!GetModuleTimeDateStamp(process_, load_address, &module_time_date_stamp)) - return; - - // Forward this to the module database. - module_database_->OnModuleLoad(process_id_, creation_time_, module_path, - module_size, module_time_date_stamp, - load_address); -} - -void ModuleEventSinkImpl::OnModuleUnload(uint64_t load_address) { - // Forward this directly to the module database. - module_database_->OnModuleUnload(process_id_, creation_time_, - static_cast<uintptr_t>(load_address)); -}
diff --git a/chrome/browser/conflicts/module_event_sink_impl_win.h b/chrome/browser/conflicts/module_event_sink_impl_win.h deleted file mode 100644 index 5f5b7ce..0000000 --- a/chrome/browser/conflicts/module_event_sink_impl_win.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CONFLICTS_MODULE_EVENT_SINK_IMPL_WIN_H_ -#define CHROME_BROWSER_CONFLICTS_MODULE_EVENT_SINK_IMPL_WIN_H_ - -#include <stdint.h> - -#include "base/process/process_handle.h" -#include "chrome/common/conflicts/module_event_sink_win.mojom.h" -#include "content/public/common/process_type.h" - -class ModuleDatabase; - -// Implementation of the mojom::ModuleEventSink interface. This is the endpoint -// in the browser process. This redirects calls to the singleton ModuleDatabase -// object. -class ModuleEventSinkImpl : public mojom::ModuleEventSink { - public: - // Creates a service endpoint that forwards notifications from the remote - // |process| of the provided |process_type| to the provided |module_database|. - // The |module_database| must outlive this object. - ModuleEventSinkImpl(base::ProcessHandle process, - content::ProcessType process_type, - ModuleDatabase* module_database); - ~ModuleEventSinkImpl() override; - - // Factory function for use with service_manager::InterfaceRegistry. This - // creates a concrete implementation of mojom::ModuleDatabase interface in the - // current process, for the remote process represented by the provided - // |request|. This should only be called on the UI thread. - static void Create(base::ProcessHandle process, - content::ProcessType process_type, - ModuleDatabase* module_database, - mojom::ModuleEventSinkRequest request); - - // mojom::ModuleEventSink implementation: - void OnModuleEvent(mojom::ModuleEventType event_type, - uint64_t load_address) override; - - bool in_error() const { return in_error_; } - - private: - friend class ModuleEventSinkImplTest; - - // OnModuleEvent disptaches to these two functions depending on the event - // type. - void OnModuleLoad(uint64_t load_address); - void OnModuleUnload(uint64_t load_address); - - // A handle to the process on the other side of the pipe. - base::ProcessHandle process_; - - // The module database this forwards events to. The |module_database| must - // outlive this object. - ModuleDatabase* module_database_; - - // The process ID of the remote process on the other end of the pipe. This is - // forwarded along to the ModuleDatabase for each call. - uint32_t process_id_; - - // The creation time of the process. Combined with process_id_ this uniquely - // identifies a process. - uint64_t creation_time_; - - // Indicates whether or not this connection is in an error mode. If true then - // all communication from the remote client is silently dropped. - bool in_error_; - - DISALLOW_COPY_AND_ASSIGN(ModuleEventSinkImpl); -}; - -#endif // CHROME_BROWSER_CONFLICTS_MODULE_EVENT_SINK_IMPL_WIN_H_
diff --git a/chrome/browser/conflicts/module_event_sink_impl_win_unittest.cc b/chrome/browser/conflicts/module_event_sink_impl_win_unittest.cc deleted file mode 100644 index 8b88fce..0000000 --- a/chrome/browser/conflicts/module_event_sink_impl_win_unittest.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/conflicts/module_event_sink_impl_win.h" - -#include <memory> - -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "chrome/browser/conflicts/module_database_win.h" -#include "chrome/common/conflicts/module_watcher_win.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// The address of this module in memory. The linker will take care of defining -// this symbol. -extern "C" IMAGE_DOS_HEADER __ImageBase; - -// An invalid load address. -const uint64_t kInvalidLoadAddress = 0xDEADBEEF; - -} // namespace - -class ModuleEventSinkImplTest : public testing::Test { - protected: - ModuleEventSinkImplTest() - : message_loop_(base::MakeUnique<base::MessageLoop>()), - module_database_( - base::MakeUnique<ModuleDatabase>(message_loop_->task_runner())) {} - - void CreateModuleSinkImpl() { - module_event_sink_impl_ = base::MakeUnique<ModuleEventSinkImpl>( - ::GetCurrentProcess(), content::PROCESS_TYPE_BROWSER, - module_database_.get()); - } - - ModuleDatabase* module_database() { - return module_event_sink_impl_->module_database_; - } - - const ModuleDatabase::ModuleMap& modules() { - return module_database_->modules_; - } - - const ModuleDatabase::ProcessMap& processes() { - return module_database_->processes_; - } - - uint32_t process_id() { return module_event_sink_impl_->process_id_; } - - std::unique_ptr<base::MessageLoop> message_loop_; - std::unique_ptr<ModuleDatabase> module_database_; - std::unique_ptr<ModuleEventSinkImpl> module_event_sink_impl_; - - private: - DISALLOW_COPY_AND_ASSIGN(ModuleEventSinkImplTest); -}; - -TEST_F(ModuleEventSinkImplTest, CallsForwardedAsExpected) { - const uintptr_t kValidLoadAddress = reinterpret_cast<uintptr_t>(&__ImageBase); - - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(0u, processes().size()); - - // Construction should immediately fire off a call to OnProcessStarted and - // create a process entry in the module database. - CreateModuleSinkImpl(); - EXPECT_EQ(module_database_.get(), module_database()); - EXPECT_EQ(::GetCurrentProcessId(), process_id()); - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // An invalid load event should not cause a module entry. - module_event_sink_impl_->OnModuleEvent( - mojom::ModuleEventType::MODULE_ALREADY_LOADED, kInvalidLoadAddress); - EXPECT_EQ(0u, modules().size()); - EXPECT_EQ(1u, processes().size()); - - // A valid load event should cause a module entry. - module_event_sink_impl_->OnModuleEvent(mojom::ModuleEventType::MODULE_LOADED, - kValidLoadAddress); - EXPECT_EQ(1u, modules().size()); - EXPECT_EQ(1u, processes().size()); -}
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index a46af89..9bee026 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -121,8 +121,9 @@ }; // Tests that message passing between extensions and content scripts works. -#if defined(MEMORY_SANITIZER) -// https://crbug.com/582185 +#if defined(MEMORY_SANITIZER) || defined(OS_MACOSX) +// https://crbug.com/582185 - flakily times out on Linux/CrOS MSAN +// https://crbug.com/681705 - flakily times out on mac_chromium_rel_ng #define MAYBE_Messaging DISABLED_Messaging #else #define MAYBE_Messaging Messaging
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc index f7df24d..1e06186 100644 --- a/chrome/browser/installable/installable_manager.cc +++ b/chrome/browser/installable/installable_manager.cc
@@ -9,11 +9,14 @@ #include "chrome/browser/manifest/manifest_icon_downloader.h" #include "chrome/browser/manifest/manifest_icon_selector.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ssl/security_state_tab_helper.h" +#include "components/security_state/core/security_state.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/service_worker_context.h" #include "content/public/browser/storage_partition.h" +#include "net/base/url_util.h" #include "third_party/WebKit/public/platform/WebDisplayMode.h" namespace { @@ -95,6 +98,23 @@ InstallableManager::~InstallableManager() = default; // static +bool InstallableManager::IsContentSecure(content::WebContents* web_contents) { + if (!web_contents) + return false; + + // Whitelist localhost. Check the VisibleURL to match what the + // SecurityStateTabHelper looks at. + if (net::IsLocalhost(web_contents->GetVisibleURL().HostNoBrackets())) + return true; + + security_state::SecurityInfo security_info; + SecurityStateTabHelper::FromWebContents(web_contents) + ->GetSecurityInfo(&security_info); + return security_info.security_level == security_state::SECURE || + security_info.security_level == security_state::EV_SECURE; +} + +// static int InstallableManager::GetMinimumIconSizeInPx() { return kIconMinimumSizeInPx; } @@ -115,12 +135,13 @@ InstallableManager::IconProperty& InstallableManager::GetIcon( const InstallableParams& params) { - return icons_[{params.ideal_icon_size_in_px, params.minimum_icon_size_in_px}]; + return icons_[{params.ideal_primary_icon_size_in_px, + params.minimum_primary_icon_size_in_px}]; } bool InstallableManager::IsIconFetched(const InstallableParams& params) const { - const auto it = icons_.find( - {params.ideal_icon_size_in_px, params.minimum_icon_size_in_px}); + const auto it = icons_.find({params.ideal_primary_icon_size_in_px, + params.minimum_primary_icon_size_in_px}); return it != icons_.end() && it->second.fetched; } @@ -136,7 +157,7 @@ if (params.check_installable && installable_->error != NO_ERROR_DETECTED) return installable_->error; - if (params.fetch_valid_icon) { + if (params.fetch_valid_primary_icon) { IconProperty& icon = GetIcon(params); if (icon.error != NO_ERROR_DETECTED) return icon.error; @@ -186,7 +207,7 @@ // b. the resource has been fetched/checked. return manifest_->fetched && (!params.check_installable || installable_->fetched) && - (!params.fetch_valid_icon || IsIconFetched(params)); + (!params.fetch_valid_primary_icon || IsIconFetched(params)); } void InstallableManager::Reset() { @@ -217,8 +238,8 @@ code, manifest_url(), manifest(), - params.fetch_valid_icon ? icon.url : GURL::EmptyGURL(), - params.fetch_valid_icon ? icon.icon.get() : nullptr, + params.fetch_valid_primary_icon ? icon.url : GURL::EmptyGURL(), + params.fetch_valid_primary_icon ? icon.icon.get() : nullptr, params.check_installable ? is_installable() : false}; task.second.Run(data); @@ -253,7 +274,7 @@ FetchManifest(); else if (params.check_installable && !installable_->fetched) CheckInstallable(); - else if (params.fetch_valid_icon && !IsIconFetched(params)) + else if (params.fetch_valid_primary_icon && !IsIconFetched(params)) CheckAndFetchBestIcon(); else NOTREACHED(); @@ -381,15 +402,15 @@ icon.fetched = true; GURL icon_url = ManifestIconSelector::FindBestMatchingIcon( - manifest().icons, params.ideal_icon_size_in_px, - params.minimum_icon_size_in_px); + manifest().icons, params.ideal_primary_icon_size_in_px, + params.minimum_primary_icon_size_in_px); if (icon_url.is_empty()) { icon.error = NO_ACCEPTABLE_ICON; } else { bool can_download_icon = ManifestIconDownloader::Download( - GetWebContents(), icon_url, params.ideal_icon_size_in_px, - params.minimum_icon_size_in_px, + GetWebContents(), icon_url, params.ideal_primary_icon_size_in_px, + params.minimum_primary_icon_size_in_px, base::Bind(&InstallableManager::OnAppIconFetched, weak_factory_.GetWeakPtr(), icon_url)); if (can_download_icon)
diff --git a/chrome/browser/installable/installable_manager.h b/chrome/browser/installable/installable_manager.h index 5dbd659b..3906abe 100644 --- a/chrome/browser/installable/installable_manager.h +++ b/chrome/browser/installable/installable_manager.h
@@ -25,20 +25,22 @@ // Data is cached and fetched in the order specified in this struct. A web app // manifest will always be fetched first. struct InstallableParams { - // The ideal icon size to fetch. Used only if |fetch_valid_icon| is true. - int ideal_icon_size_in_px = -1; + // The ideal primary icon size to fetch. Used only if + // |fetch_valid_primary_icon| is true. + int ideal_primary_icon_size_in_px = -1; - // The minimum icon size to fetch. Used only if |fetch_valid_icon| is true. - int minimum_icon_size_in_px = -1; + // The minimum primary icon size to fetch. Used only if + // |fetch_valid_primary_icon| is true. + int minimum_primary_icon_size_in_px = -1; // Check whether the site is installable. That is, it has a manifest valid for // a web app and a service worker controlling the manifest start URL and the // current URL. bool check_installable = false; - // Check whether there is an icon in the manifest conforming to the icon size - // parameters, and that the icon can be fetched and isn't an empty bitmap. - bool fetch_valid_icon = false; + // Check whether there is a fetchable, non-empty icon in the manifest + // conforming to the primary icon size parameters. + bool fetch_valid_primary_icon = false; }; // This struct is passed to an InstallableCallback when the InstallableManager @@ -55,14 +57,15 @@ // Empty if the site has an unparseable manifest. const content::Manifest& manifest; - // Empty if no icon was requested. - const GURL& icon_url; + // Empty if no primary_icon was requested. + const GURL& primary_icon_url; - // nullptr if the most appropriate icon couldn't be determined or downloaded. - // The underlying icon is owned by the InstallableManager; clients must copy - // the bitmap if they want to to use it. If fetch_valid_icon was true and an - // icon could not be retrieved, the reason will be in error_code. - const SkBitmap* icon; + // nullptr if the most appropriate primary icon couldn't be determined or + // downloaded. The underlying primary icon is owned by the InstallableManager; + // clients must copy the bitmap if they want to to use it. If + // fetch_valid_primary_icon was true and a primary icon could not be + // retrieved, the reason will be in error_code. + const SkBitmap* primary_icon; // true if the site has a service worker and a viable web app manifest. If // check_installable was true and the site isn't installable, the reason will @@ -81,6 +84,10 @@ explicit InstallableManager(content::WebContents* web_contents); ~InstallableManager() override; + // Returns true if the overall security state of |web_contents| is sufficient + // to be considered installable. + static bool IsContentSecure(content::WebContents* web_contents); + // Returns the minimum icon size in pixels for a site to be installable. // TODO(dominickn): consolidate this concept with minimum_icon_size_in_px // across all platforms.
diff --git a/chrome/browser/installable/installable_manager_browsertest.cc b/chrome/browser/installable/installable_manager_browsertest.cc index 405b1fe..f75d21e 100644 --- a/chrome/browser/installable/installable_manager_browsertest.cc +++ b/chrome/browser/installable/installable_manager_browsertest.cc
@@ -19,24 +19,24 @@ InstallableParams GetManifestParams() { InstallableParams params; params.check_installable = false; - params.fetch_valid_icon = false; + params.fetch_valid_primary_icon = false; return params; } InstallableParams GetWebAppParams() { InstallableParams params = GetManifestParams(); - params.ideal_icon_size_in_px = 144; - params.minimum_icon_size_in_px = 144; + params.ideal_primary_icon_size_in_px = 144; + params.minimum_primary_icon_size_in_px = 144; params.check_installable = true; - params.fetch_valid_icon = true; + params.fetch_valid_primary_icon = true; return params; } InstallableParams GetIconParams() { InstallableParams params = GetManifestParams(); - params.ideal_icon_size_in_px = 144; - params.minimum_icon_size_in_px = 144; - params.fetch_valid_icon = true; + params.ideal_primary_icon_size_in_px = 144; + params.minimum_primary_icon_size_in_px = 144; + params.fetch_valid_primary_icon = true; return params; } @@ -51,9 +51,9 @@ error_code_ = data.error_code; manifest_url_ = data.manifest_url; manifest_ = data.manifest; - icon_url_ = data.icon_url; - if (data.icon) - icon_.reset(new SkBitmap(*data.icon)); + icon_url_ = data.primary_icon_url; + if (data.primary_icon) + icon_.reset(new SkBitmap(*data.primary_icon)); is_installable_ = data.is_installable; base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); } @@ -92,9 +92,9 @@ error_code_ = data.error_code; manifest_url_ = data.manifest_url; manifest_ = data.manifest; - icon_url_ = data.icon_url; - if (data.icon) - icon_.reset(new SkBitmap(*data.icon)); + icon_url_ = data.primary_icon_url; + if (data.primary_icon) + icon_.reset(new SkBitmap(*data.primary_icon)); is_installable_ = data.is_installable; manager_->GetData(params_, @@ -105,8 +105,8 @@ void OnDidFinishSecondCheck(const InstallableData& data) { EXPECT_EQ(error_code_, data.error_code); EXPECT_EQ(manifest_url_, data.manifest_url); - EXPECT_EQ(icon_url_, data.icon_url); - EXPECT_EQ(icon_.get(), data.icon); + EXPECT_EQ(icon_url_, data.primary_icon_url); + EXPECT_EQ(icon_.get(), data.primary_icon); EXPECT_EQ(is_installable_, data.is_installable); EXPECT_EQ(manifest_.IsEmpty(), data.manifest.IsEmpty()); EXPECT_EQ(manifest_.start_url, data.manifest.start_url); @@ -348,8 +348,8 @@ new CallbackTester(run_loop.QuitClosure())); InstallableParams params = GetWebAppParams(); - params.ideal_icon_size_in_px = 96; - params.minimum_icon_size_in_px = 96; + params.ideal_primary_icon_size_in_px = 96; + params.minimum_primary_icon_size_in_px = 96; RunInstallableManager(tester.get(), params); run_loop.Run(); @@ -572,8 +572,8 @@ // Dial up the icon size requirements to something that isn't available. // This should now fail with NoIconMatchingRequirements. InstallableParams params = GetWebAppParams(); - params.ideal_icon_size_in_px = 2000; - params.minimum_icon_size_in_px = 2000; + params.ideal_primary_icon_size_in_px = 2000; + params.minimum_primary_icon_size_in_px = 2000; RunInstallableManager(tester.get(), params); run_loop.Run(); @@ -594,8 +594,8 @@ // This should fail with NoIconMatchingRequirements. InstallableParams params = GetWebAppParams(); - params.ideal_icon_size_in_px = 2000; - params.minimum_icon_size_in_px = 2000; + params.ideal_primary_icon_size_in_px = 2000; + params.minimum_primary_icon_size_in_px = 2000; NavigateAndRunInstallableManager(tester.get(), params, "/banners/manifest_test_page.html"); run_loop.Run();
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 477e507..263632c 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -198,6 +198,7 @@ #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/device_status_collector.h" +#include "chrome/browser/chromeos/policy/dm_token_storage.h" #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" #include "chrome/browser/chromeos/power/power_prefs.h" #include "chrome/browser/chromeos/preferences.h" @@ -444,6 +445,7 @@ policy::BrowserPolicyConnectorChromeOS::RegisterPrefs(registry); policy::DeviceCloudPolicyManagerChromeOS::RegisterPrefs(registry); policy::DeviceStatusCollector::RegisterPrefs(registry); + policy::DMTokenStorage::RegisterPrefs(registry); policy::PolicyCertServiceFactory::RegisterPrefs(registry); quirks::QuirksManager::RegisterPrefs(registry);
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index e675552..1659cdc2 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -331,8 +331,10 @@ setMDMode_: function() { if (loadTimeData.getString('newOobeUI') == 'on') { $('oobe').setAttribute('md-mode', 'true'); + $('oobe-shield').setAttribute('md-mode', 'true'); } else { $('oobe').removeAttribute('md-mode'); + $('oobe-shield').removeAttribute('md-mode'); } }, };
diff --git a/chrome/browser/resources/chromeos/login/oobe_a11y_option.css b/chrome/browser/resources/chromeos/login/oobe_a11y_option.css index 87f86c42..280b5b8 100644 --- a/chrome/browser/resources/chromeos/login/oobe_a11y_option.css +++ b/chrome/browser/resources/chromeos/login/oobe_a11y_option.css
@@ -9,12 +9,15 @@ } #elementBox { + padding: 0 10px; width: inherit; } paper-toggle-button { + /* paper-toggle-button has fixed width of 36px. Make it 32. */ + -webkit-transform: scale(.8888); min-height: 20px; - min-width: 36px; + min-width: 32px; } #titleContainer {
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.css b/chrome/browser/resources/chromeos/login/oobe_dialog.css index 4f996e8a..5dabdd2 100644 --- a/chrome/browser/resources/chromeos/login/oobe_dialog.css +++ b/chrome/browser/resources/chromeos/login/oobe_dialog.css
@@ -10,19 +10,10 @@ min-height: 84px; /* 64 title + 20 subtitle */ } -:host([welcome-screen]) .oobe-header { - height: 64px; - min-height: unset; -} - #footer-container { padding: 44px 64px 0 64px; } -:host([welcome-screen]) #footer-container { - padding-top: 32px; -} - #oobe-bottom { box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.14); height: 80px;
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog_parameters.css b/chrome/browser/resources/chromeos/login/oobe_dialog_parameters.css index 01b2a77..8583252 100644 --- a/chrome/browser/resources/chromeos/login/oobe_dialog_parameters.css +++ b/chrome/browser/resources/chromeos/login/oobe_dialog_parameters.css
@@ -20,15 +20,10 @@ margin: 36px 0 0 0; /* = 64 - font height*/ } -oobe-dialog[welcome-screen] h1.title { - font-size: 38px; - margin: 22px 0 0 0; /* = 64 - font height*/ -} - oobe-dialog .subtitle { color: rgba(0, 0, 0, 0.87); font-size: 13px; - margin: 27px 0 0 0; /* = 40 - line-height */ + margin: 23px 0 0 0; /* = 40 - 4 (adjustment) - line-height */ } oobe-dialog .bottom-buttons {
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.css b/chrome/browser/resources/chromeos/login/oobe_eula.css index 390d952..44b8810 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.css +++ b/chrome/browser/resources/chromeos/login/oobe_eula.css
@@ -11,7 +11,6 @@ #installationSettings, #logging { font: 13px Roboto, sans-serif; - margin: 0 20px; } #installationSettings { @@ -24,17 +23,14 @@ } #usageStats { - --paper-checkbox-size: 16px; + --paper-checkbox-size: 20px; + --paper-checkbox-checked-color: rgb(66, 133, 244); /* #4285f4 */ /* End padding must be greater than --paper-checkbox-label-spacing */ -webkit-padding-end: 16px; max-width: 550px; padding-bottom: 20px; } -#accept-button-text { - text-transform: uppercase; -} - .bottom-buttons { padding: 0 6px; /* = 8px - 2px back button border */ }
diff --git a/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.css b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.css index ab3d4cf..196a220 100644 --- a/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.css +++ b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.css
@@ -11,3 +11,7 @@ #container { height: 100%; } + +#container select { + width: 100%; +}
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.css b/chrome/browser/resources/chromeos/login/oobe_welcome.css index 2315acd..45b61aac 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome.css +++ b/chrome/browser/resources/chromeos/login/oobe_welcome.css
@@ -6,7 +6,7 @@ #languageScreen .language-selection-entry { border-top: 1px solid lightgrey; height: 44px; - padding: 0 20px; + padding: 0 10px; } #languageScreen .language-selection-entry:last-of-type {
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome_dialog.css b/chrome/browser/resources/chromeos/login/oobe_welcome_dialog.css index ca71ad5..cc90904 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome_dialog.css +++ b/chrome/browser/resources/chromeos/login/oobe_welcome_dialog.css
@@ -14,12 +14,13 @@ color: rgba(0, 0, 0, 0.87); font-family: Roboto, sans-serif; font-size: 38px; - font-weight: normal; + font-weight: 300; /* roboto-light */ margin: 120px 0 30px 0; } #welcomeIllustration { height: 300px; + padding-top: 14px; width: 390px; }
diff --git a/chrome/browser/resources/chromeos/login/screen_container.html b/chrome/browser/resources/chromeos/login/screen_container.html index 87d5781..f258aa4 100644 --- a/chrome/browser/resources/chromeos/login/screen_container.html +++ b/chrome/browser/resources/chromeos/login/screen_container.html
@@ -3,6 +3,7 @@ <include src="api_keys_notice.html"> <div id="scroll-container"> <div id="outer-container" class="down"> + <div id="oobe-shield"></div> <div id="oobe" class="faded"> <div id="inner-container" class="down"> <div id="step-logo" hidden>
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index de0ea0a..3b8501e 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -614,7 +614,7 @@ "//ui/strings", "//ui/surface", "//ui/web_dialogs", - "//v8", + "//v8:v8_version", ] allow_circular_includes_from = [] @@ -1511,8 +1511,6 @@ "views/subtle_notification_view.h", "views/sync/bubble_sync_promo_view.cc", "views/sync/bubble_sync_promo_view.h", - "views/sync/profile_signin_confirmation_dialog_views.cc", - "views/sync/profile_signin_confirmation_dialog_views.h", "views/task_manager_view.cc", "views/task_manager_view.h", "views/website_settings/chosen_object_row.cc", @@ -1564,6 +1562,8 @@ "views/screen_capture_notification_ui_views.cc", "views/sync/one_click_signin_dialog_view.cc", "views/sync/one_click_signin_dialog_view.h", + "views/sync/profile_signin_confirmation_dialog_views.cc", + "views/sync/profile_signin_confirmation_dialog_views.h", ] }
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h index a596b90..d23724f 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h
@@ -38,17 +38,16 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, + ui::ProfileSigninConfirmationDelegate* delegate, bool offer_profile_creation); virtual ~ProfileSigninConfirmationDialogCocoa(); // Shows the dialog if needed. - static void Show( - Browser* browser, - content::WebContents* web_contents, - Profile* profile, - const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); + static void Show(Browser* browser, + content::WebContents* web_contents, + Profile* profile, + const std::string& username, + ui::ProfileSigninConfirmationDelegate* delegate); // Closes the dialog, which deletes itself. void Close();
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm index eab52ff..dbd031b 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.mm
@@ -16,15 +16,19 @@ namespace { // static -void ShowDialog(Browser* browser, - content::WebContents* web_contents, - Profile* profile, - const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, - bool offer_profile_creation) { +void ShowDialog( + Browser* browser, + content::WebContents* web_contents, + Profile* profile, + const std::string& username, + ui::ProfileSigninConfirmationDelegate* delegate, + bool offer_profile_creation) { // The dialog owns itself. - new ProfileSigninConfirmationDialogCocoa(browser, web_contents, profile, - username, std::move(delegate), + new ProfileSigninConfirmationDialogCocoa(browser, + web_contents, + profile, + username, + delegate, offer_profile_creation); } @@ -35,18 +39,19 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate, + ui::ProfileSigninConfirmationDelegate* delegate, bool offer_profile_creation) { // Setup the dialog view controller. const base::Closure& closeDialogCallback = base::Bind(&ProfileSigninConfirmationDialogCocoa::Close, base::Unretained(this)); - controller_.reset([[ProfileSigninConfirmationViewController alloc] - initWithBrowser:browser - username:username - delegate:std::move(delegate) - closeDialogCallback:closeDialogCallback - offerProfileCreation:offer_profile_creation]); + controller_.reset( + [[ProfileSigninConfirmationViewController alloc] + initWithBrowser:browser + username:username + delegate:delegate + closeDialogCallback:closeDialogCallback + offerProfileCreation:offer_profile_creation]); // Setup the constrained window that will show the view. base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc] @@ -66,10 +71,10 @@ content::WebContents* web_contents, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { + ui::ProfileSigninConfirmationDelegate* delegate) { ui::CheckShouldPromptForNewProfile( profile, base::Bind(ShowDialog, browser, web_contents, profile, username, - base::Passed(std::move(delegate)))); + delegate)); } void ProfileSigninConfirmationDialogCocoa::Close() {
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h index 8e4a35c..2a70b08 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_UI_COCOA_PROFILES_PROFILE_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_ #import <Cocoa/Cocoa.h> -#include <memory> #include <string> #include "base/callback.h" @@ -34,7 +33,7 @@ bool offerProfileCreation_; // Dialog button callbacks. - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate_; + ui::ProfileSigninConfirmationDelegate* delegate_; base::Closure closeDialogCallback_; // UI elements. @@ -49,12 +48,10 @@ } - (id)initWithBrowser:(Browser*)browser - username:(const std::string&)username - delegate: - (std::unique_ptr<ui::ProfileSigninConfirmationDelegate>) - delegate - closeDialogCallback:(const base::Closure&)closeDialogCallback - offerProfileCreation:(bool)offer; + username:(const std::string&)username + delegate:(ui::ProfileSigninConfirmationDelegate*)delegate + closeDialogCallback:(const base::Closure&)closeDialogCallback + offerProfileCreation:(bool)offer; - (IBAction)cancel:(id)sender; - (IBAction)ok:(id)sender; - (IBAction)close:(id)sender; @@ -62,4 +59,12 @@ @end +@interface ProfileSigninConfirmationViewController (TestingAPI) + +@property(readonly, nonatomic) ui::ProfileSigninConfirmationDelegate* delegate; +@property(readonly, nonatomic) NSButton* createProfileButton; +@property(readonly, nonatomic) NSTextView* explanationField; + +@end + #endif // CHROME_BROWSER_UI_COCOA_PROFILES_PROFILE_SIGNIN_CONFIRMATION_VIEW_CONTROLLER_
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm index 28f0873..5a7480f 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller.mm
@@ -142,16 +142,14 @@ @implementation ProfileSigninConfirmationViewController - (id)initWithBrowser:(Browser*)browser - username:(const std::string&)username - delegate: - (std::unique_ptr<ui::ProfileSigninConfirmationDelegate>) - delegate - closeDialogCallback:(const base::Closure&)closeDialogCallback - offerProfileCreation:(bool)offer { + username:(const std::string&)username + delegate:(ui::ProfileSigninConfirmationDelegate*)delegate + closeDialogCallback:(const base::Closure&)closeDialogCallback + offerProfileCreation:(bool)offer { if ((self = [super initWithNibName:nil bundle:nil])) { browser_ = browser; username_ = username; - delegate_ = std::move(delegate); + delegate_ = delegate; closeDialogCallback_ = closeDialogCallback; offerProfileCreation_ = offer; } @@ -378,7 +376,7 @@ - (IBAction)cancel:(id)sender { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = nullptr; + delegate_ = NULL; closeDialogCallback_.Run(); } } @@ -386,7 +384,7 @@ - (IBAction)ok:(id)sender { if (delegate_) { delegate_->OnContinueSignin(); - delegate_ = nullptr; + delegate_ = NULL; closeDialogCallback_.Run(); } } @@ -394,7 +392,7 @@ - (IBAction)close:(id)sender { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = nullptr; + delegate_ = NULL; } closeDialogCallback_.Run(); } @@ -402,7 +400,7 @@ - (IBAction)createProfile:(id)sender { if (delegate_) { delegate_->OnSigninWithNewProfile(); - delegate_ = nullptr; + delegate_ = NULL; closeDialogCallback_.Run(); } } @@ -442,3 +440,19 @@ } @end + +@implementation ProfileSigninConfirmationViewController (TestingAPI) + +- (ui::ProfileSigninConfirmationDelegate*)delegate { + return delegate_; +} + +- (NSButton*)createProfileButton { + return createProfileButton_.get(); +} + +- (NSTextView*)explanationField { + return explanationField_.get(); +} + +@end
diff --git a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm index 4311f676..6380427 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_view_controller_browsertest.mm
@@ -18,32 +18,10 @@ #import "testing/gtest_mac.h" #include "ui/base/l10n/l10n_util.h" -@interface ProfileSigninConfirmationViewController (TestingAPI) - -@property(readonly, nonatomic) ui::ProfileSigninConfirmationDelegate* delegate; -@property(readonly, nonatomic) NSButton* createProfileButton; -@property(readonly, nonatomic) NSTextView* explanationField; - -@end - -@implementation ProfileSigninConfirmationViewController (TestingAPI) - -- (ui::ProfileSigninConfirmationDelegate*)delegate { - return delegate_.get(); -} - -- (NSButton*)createProfileButton { - return createProfileButton_.get(); -} - -- (NSTextView*)explanationField { - return explanationField_.get(); -} - -@end - class ProfileSigninConfirmationViewControllerTest - : public InProcessBrowserTest { + : public InProcessBrowserTest, + public ui::ProfileSigninConfirmationDelegate { + public: ProfileSigninConfirmationViewControllerTest() : window_(nil), @@ -66,11 +44,11 @@ &ProfileSigninConfirmationViewControllerTest::OnClose, base::Unretained(this)); controller_.reset([[ProfileSigninConfirmationViewController alloc] - initWithBrowser:browser() - username:username() - delegate:base::MakeUnique<TestSigninDelegate>(this) - closeDialogCallback:close - offerProfileCreation:offerProfileCreation]); + initWithBrowser:browser() + username:username() + delegate:this + closeDialogCallback:close + offerProfileCreation:offerProfileCreation]); [[window_ contentView] addSubview:[controller_ view]]; [window_ makeKeyAndOrderFront:NSApp]; ASSERT_TRUE([window_ isVisible]); @@ -85,6 +63,10 @@ IDS_ENTERPRISE_SIGNIN_PROFILE_LINK_LEARN_MORE); } + // ui::ProfileSigninConfirmationDelegate: + void OnContinueSignin() override { continued_ = true; } + void OnCancelSignin() override { cancelled_ = true; } + void OnSigninWithNewProfile() override { created_ = true; } void OnClose() { closed_ = true; } // The window containing the dialog. @@ -100,23 +82,6 @@ bool closed_; private: - class TestSigninDelegate : public ui::ProfileSigninConfirmationDelegate { - public: - explicit TestSigninDelegate( - ProfileSigninConfirmationViewControllerTest* client) - : client_(client) {} - - // ui::ProfileSigninConfirmationDelegate: - void OnContinueSignin() override { client_->continued_ = true; } - void OnCancelSignin() override { client_->cancelled_ = true; } - void OnSigninWithNewProfile() override { client_->created_ = true; } - - private: - ProfileSigninConfirmationViewControllerTest* client_; - - DISALLOW_COPY_AND_ASSIGN(TestSigninDelegate); - }; - DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationViewControllerTest); };
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h index 4d81b16..1eb2bd5 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h +++ b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.h
@@ -24,7 +24,7 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; + ui::ProfileSigninConfirmationDelegate* delegate) override; void ShowManagePasswordsBubble(bool user_action) override; void HideManagePasswordsBubble() override; base::WeakPtr<ValidationMessageBubble> ShowValidationMessage(
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm index a66b2ee..bc20ecf6 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm +++ b/chrome/browser/ui/cocoa/tab_dialogs_cocoa.mm
@@ -11,7 +11,6 @@ #import "chrome/browser/ui/cocoa/profiles/profile_signin_confirmation_dialog_cocoa.h" #include "chrome/browser/ui/cocoa/tab_dialogs_views_mac.h" #import "chrome/browser/ui/cocoa/validation_message_bubble_cocoa.h" -#include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" #include "content/public/browser/web_contents.h" #include "ui/base/material_design/material_design_controller.h" @@ -65,9 +64,9 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { - ProfileSigninConfirmationDialogCocoa::Show(browser, web_contents_, profile, - username, std::move(delegate)); + ui::ProfileSigninConfirmationDelegate* delegate) { + ProfileSigninConfirmationDialogCocoa::Show( + browser, web_contents_, profile, username, delegate); } void TabDialogsCocoa::ShowManagePasswordsBubble(bool user_action) {
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h index 980201b..622777c 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h +++ b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.h
@@ -15,11 +15,6 @@ // TabDialogs: void ShowCollectedCookies() override; - void ShowProfileSigninConfirmation( - Browser* browser, - Profile* profile, - const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; private: DISALLOW_COPY_AND_ASSIGN(TabDialogsViewsMac);
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm index d71c1f2..6187e48 100644 --- a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm +++ b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm
@@ -5,7 +5,6 @@ #include "chrome/browser/ui/cocoa/tab_dialogs_views_mac.h" #include "chrome/browser/ui/views/collected_cookies_views.h" -#include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h" TabDialogsViewsMac::TabDialogsViewsMac(content::WebContents* contents) : TabDialogsCocoa(contents) {} @@ -16,12 +15,3 @@ // Deletes itself on close. new CollectedCookiesViews(web_contents()); } - -void TabDialogsViewsMac::ShowProfileSigninConfirmation( - Browser* browser, - Profile* profile, - const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { - ProfileSigninConfirmationDialogViews::ShowDialog(browser, profile, username, - std::move(delegate)); -}
diff --git a/chrome/browser/ui/collected_cookies_browsertest.cc b/chrome/browser/ui/collected_cookies_browsertest.cc index e946733..0316265 100644 --- a/chrome/browser/ui/collected_cookies_browsertest.cc +++ b/chrome/browser/ui/collected_cookies_browsertest.cc
@@ -22,7 +22,7 @@ public: CollectedCookiesTest() {} - // DialogBrowserTest: + // TestDialogInterface: void ShowDialog(const std::string& name) override { ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc index 672c4c3..75b3376 100644 --- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc +++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -242,11 +242,11 @@ content::RecordAction( base::UserMetricsAction("Signin_Show_EnterpriseAccountPrompt")); - TabDialogs::FromWebContents(web_contents) - ->ShowProfileSigninConfirmation(browser_, profile_, - signin->GetUsernameForAuthInProgress(), - base::MakeUnique<SigninDialogDelegate>( - weak_pointer_factory_.GetWeakPtr())); + TabDialogs::FromWebContents(web_contents)->ShowProfileSigninConfirmation( + browser_, + profile_, + signin->GetUsernameForAuthInProgress(), + new SigninDialogDelegate(weak_pointer_factory_.GetWeakPtr())); } void OneClickSigninSyncStarter::LoadPolicyWithCachedCredentials() {
diff --git a/chrome/browser/ui/tab_dialogs.h b/chrome/browser/ui/tab_dialogs.h index 41ac3c1..ca3fec18b 100644 --- a/chrome/browser/ui/tab_dialogs.h +++ b/chrome/browser/ui/tab_dialogs.h
@@ -59,7 +59,7 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) = 0; + ui::ProfileSigninConfirmationDelegate* delegate) = 0; // Shows or hides the ManagePasswords bubble. // Pass true for |user_action| if this is a user initiated action.
diff --git a/chrome/browser/ui/test/test_browser_dialog.cc b/chrome/browser/ui/test/test_browser_dialog.cc index 18099e7..5faa2fa 100644 --- a/chrome/browser/ui/test/test_browser_dialog.cc +++ b/chrome/browser/ui/test/test_browser_dialog.cc
@@ -88,11 +88,11 @@ gfx::NativeView parent = platform_util::GetViewForWindow(DialogParent()); views::Widget::Widgets widgets_before; - views::Widget::GetAllOwnedWidgets(parent, &widgets_before); + views::Widget::GetAllChildWidgets(parent, &widgets_before); ShowDialog(NameFromTestCase()); views::Widget::Widgets widgets_after; - views::Widget::GetAllOwnedWidgets(parent, &widgets_after); + views::Widget::GetAllChildWidgets(parent, &widgets_after); auto added = base::STLSetDifference<std::vector<views::Widget*>>( widgets_after, widgets_before);
diff --git a/chrome/browser/ui/views/ime_driver/ime_driver_mus.cc b/chrome/browser/ui/views/ime_driver/ime_driver_mus.cc index 5ce2fb3a..a4e267e 100644 --- a/chrome/browser/ui/views/ime_driver/ime_driver_mus.cc +++ b/chrome/browser/ui/views/ime_driver/ime_driver_mus.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/ime_driver/ime_driver_mus.h" #include "base/memory/ptr_util.h" +#include "chrome/browser/ui/views/ime_driver/remote_text_input_client.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/service_manager_connection.h" #include "mojo/public/cpp/bindings/strong_binding.h" @@ -38,15 +39,18 @@ ime_registrar->RegisterDriver(std::move(ime_driver_ptr)); } -void IMEDriver::StartSession( - int32_t session_id, - ui::mojom::TextInputClientPtr client, - ui::mojom::InputMethodRequest input_method_request) { +void IMEDriver::StartSession(int32_t session_id, + ui::mojom::StartSessionDetailsPtr details) { #if defined(OS_CHROMEOS) + std::unique_ptr<RemoteTextInputClient> remote_client = + base::MakeUnique<RemoteTextInputClient>( + std::move(details->client), details->text_input_type, + details->text_input_mode, details->text_direction, + details->text_input_flags, details->caret_bounds); input_method_bindings_[session_id] = base::MakeUnique<mojo::Binding<ui::mojom::InputMethod>>( - new InputMethodBridge(std::move(client)), - std::move(input_method_request)); + new InputMethodBridge(std::move(remote_client)), + std::move(details->input_method_request)); #else input_method_bindings_[session_id] = base::MakeUnique<mojo::Binding<ui::mojom::InputMethod>>(
diff --git a/chrome/browser/ui/views/ime_driver/ime_driver_mus.h b/chrome/browser/ui/views/ime_driver/ime_driver_mus.h index e81d34d..315c7b9c 100644 --- a/chrome/browser/ui/views/ime_driver/ime_driver_mus.h +++ b/chrome/browser/ui/views/ime_driver/ime_driver_mus.h
@@ -23,10 +23,8 @@ private: // ui::mojom::IMEDriver: - void StartSession( - int32_t session_id, - ui::mojom::TextInputClientPtr client, - ui::mojom::InputMethodRequest input_method_request) override; + void StartSession(int32_t session_id, + ui::mojom::StartSessionDetailsPtr details) override; void CancelSession(int32_t session_id) override; std::map<int32_t, std::unique_ptr<mojo::Binding<ui::mojom::InputMethod>>>
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc index edf5fb9..a74e7bf 100644 --- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc +++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc
@@ -7,8 +7,9 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/ui/views/ime_driver/remote_text_input_client.h" -InputMethodBridge::InputMethodBridge(ui::mojom::TextInputClientPtr client) - : client_(base::MakeUnique<RemoteTextInputClient>(std::move(client))), +InputMethodBridge::InputMethodBridge( + std::unique_ptr<RemoteTextInputClient> client) + : client_(std::move(client)), input_method_chromeos_( base::MakeUnique<ui::InputMethodChromeOS>(nullptr)) { input_method_chromeos_->SetFocusedTextInputClient(client_.get()); @@ -18,10 +19,12 @@ void InputMethodBridge::OnTextInputTypeChanged( ui::TextInputType text_input_type) { + client_->SetTextInputType(text_input_type); input_method_chromeos_->OnTextInputTypeChanged(client_.get()); } void InputMethodBridge::OnCaretBoundsChanged(const gfx::Rect& caret_bounds) { + client_->SetCaretBounds(caret_bounds); input_method_chromeos_->OnCaretBoundsChanged(client_.get()); }
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h index 4b83a725..8ca254d 100644 --- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h +++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_VIEWS_IME_DRIVER_INPUT_METHOD_BRIDGE_CHROMEOS_H_ #define CHROME_BROWSER_UI_VIEWS_IME_DRIVER_INPUT_METHOD_BRIDGE_CHROMEOS_H_ +#include "chrome/browser/ui/views/ime_driver/remote_text_input_client.h" #include "services/ui/public/interfaces/ime/ime.mojom.h" #include "ui/base/ime/input_method_chromeos.h" @@ -12,7 +13,7 @@ // forwards the received events to an instance of ui::InputMethodChromeOS. class InputMethodBridge : public ui::mojom::InputMethod { public: - explicit InputMethodBridge(ui::mojom::TextInputClientPtr client); + explicit InputMethodBridge(std::unique_ptr<RemoteTextInputClient> client); ~InputMethodBridge() override; // ui::mojom::InputMethod: @@ -23,7 +24,7 @@ void CancelComposition() override; private: - std::unique_ptr<ui::TextInputClient> client_; + std::unique_ptr<RemoteTextInputClient> client_; std::unique_ptr<ui::InputMethodChromeOS> input_method_chromeos_; DISALLOW_COPY_AND_ASSIGN(InputMethodBridge);
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc index 00435e5..6d921d7 100644 --- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc +++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc
@@ -106,7 +106,11 @@ ui::mojom::TextInputClientPtr client_ptr; client_ = base::MakeUnique<TestTextInputClient>(MakeRequest(&client_ptr)); - input_method_ = base::MakeUnique<InputMethodBridge>(std::move(client_ptr)); + input_method_ = base::MakeUnique<InputMethodBridge>( + base::MakeUnique<RemoteTextInputClient>( + std::move(client_ptr), ui::TEXT_INPUT_TYPE_TEXT, + ui::TEXT_INPUT_MODE_DEFAULT, base::i18n::LEFT_TO_RIGHT, 0, + gfx::Rect())); } bool ProcessKeyEvent(std::unique_ptr<ui::Event> event) {
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc index b7705ad0..93b7ff2 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
@@ -12,11 +12,30 @@ #include "base/strings/utf_string_conversions.h" RemoteTextInputClient::RemoteTextInputClient( - ui::mojom::TextInputClientPtr remote_client) - : remote_client_(std::move(remote_client)) {} + ui::mojom::TextInputClientPtr remote_client, + ui::TextInputType text_input_type, + ui::TextInputMode text_input_mode, + base::i18n::TextDirection text_direction, + int text_input_flags, + gfx::Rect caret_bounds) + : remote_client_(std::move(remote_client)), + text_input_type_(text_input_type), + text_input_mode_(text_input_mode), + text_direction_(text_direction), + text_input_flags_(text_input_flags), + caret_bounds_(caret_bounds) {} RemoteTextInputClient::~RemoteTextInputClient() {} +void RemoteTextInputClient::SetTextInputType( + ui::TextInputType text_input_type) { + text_input_type_ = text_input_type; +} + +void RemoteTextInputClient::SetCaretBounds(const gfx::Rect& caret_bounds) { + caret_bounds_ = caret_bounds; +} + void RemoteTextInputClient::SetCompositionText( const ui::CompositionText& composition) { remote_client_->SetCompositionText(composition); @@ -39,27 +58,19 @@ } ui::TextInputType RemoteTextInputClient::GetTextInputType() const { - // TODO(moshayedi): crbug.com/631527. - NOTIMPLEMENTED(); - return ui::TEXT_INPUT_TYPE_TEXT; + return text_input_type_; } ui::TextInputMode RemoteTextInputClient::GetTextInputMode() const { - // TODO(moshayedi): crbug.com/631527. - NOTIMPLEMENTED(); - return ui::TEXT_INPUT_MODE_DEFAULT; + return text_input_mode_; } base::i18n::TextDirection RemoteTextInputClient::GetTextDirection() const { - // TODO(moshayedi): crbug.com/631527. - NOTIMPLEMENTED(); - return base::i18n::UNKNOWN_DIRECTION; + return text_direction_; } int RemoteTextInputClient::GetTextInputFlags() const { - // TODO(moshayedi): crbug.com/631527. - NOTIMPLEMENTED(); - return 0; + return text_input_flags_; } bool RemoteTextInputClient::CanComposeInline() const { @@ -70,9 +81,7 @@ } gfx::Rect RemoteTextInputClient::GetCaretBounds() const { - // TODO(moshayedi): crbug.com/631527. - NOTIMPLEMENTED(); - return gfx::Rect(); + return caret_bounds_; } bool RemoteTextInputClient::GetCompositionCharacterBounds(
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h index 056be5f1..18ef7be44 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
@@ -13,9 +13,17 @@ // ui::InputMethod::SetFocusedTextInputClient(). class RemoteTextInputClient : public ui::TextInputClient { public: - explicit RemoteTextInputClient(ui::mojom::TextInputClientPtr remote_client); + RemoteTextInputClient(ui::mojom::TextInputClientPtr remote_client, + ui::TextInputType text_input_type, + ui::TextInputMode text_input_mode, + base::i18n::TextDirection text_direction, + int text_input_flags, + gfx::Rect caret_bounds); ~RemoteTextInputClient() override; + void SetTextInputType(ui::TextInputType text_input_type); + void SetCaretBounds(const gfx::Rect& caret_bounds); + private: // ui::TextInputClient: void SetCompositionText(const ui::CompositionText& composition) override; @@ -48,6 +56,11 @@ void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override; ui::mojom::TextInputClientPtr remote_client_; + ui::TextInputType text_input_type_; + ui::TextInputMode text_input_mode_; + base::i18n::TextDirection text_direction_; + int text_input_flags_; + gfx::Rect caret_bounds_; DISALLOW_COPY_AND_ASSIGN(RemoteTextInputClient); };
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc index 774b60956..1ee37be 100644 --- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc +++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/views/profiles/profile_chooser_view.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" @@ -21,7 +22,6 @@ #include "google_apis/gaia/gaia_auth_util.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/ui_features.h" #include "ui/gfx/font.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/range/range.h" @@ -36,17 +36,13 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/dialog_client_view.h" -#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) -#include "chrome/browser/ui/views/profiles/profile_chooser_view.h" -#endif - ProfileSigninConfirmationDialogViews::ProfileSigninConfirmationDialogViews( Browser* browser, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) + ui::ProfileSigninConfirmationDelegate* delegate) : browser_(browser), username_(username), - delegate_(std::move(delegate)), + delegate_(delegate), prompt_for_new_profile_(true) {} ProfileSigninConfirmationDialogViews::~ProfileSigninConfirmationDialogViews() {} @@ -56,8 +52,7 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { -#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) + ui::ProfileSigninConfirmationDelegate* delegate) { // Hides the new avatar bubble if it is currently shown. The new avatar bubble // should be automatically closed when it loses focus. However on windows the // profile signin confirmation dialog is not modal yet thus it does not take @@ -66,11 +61,10 @@ // TODO(guohui): removes the workaround once the profile confirmation dialog // is fixed. ProfileChooserView::Hide(); -#endif ProfileSigninConfirmationDialogViews* dialog = - new ProfileSigninConfirmationDialogViews(browser, username, - std::move(delegate)); + new ProfileSigninConfirmationDialogViews( + browser, username, delegate); ui::CheckShouldPromptForNewProfile( profile, // This callback is guaranteed to be invoked, and once it is, the dialog @@ -123,7 +117,7 @@ delegate_->OnSigninWithNewProfile(); else delegate_->OnContinueSignin(); - delegate_ = nullptr; + delegate_ = NULL; } return true; } @@ -131,7 +125,7 @@ bool ProfileSigninConfirmationDialogViews::Cancel() { if (delegate_) { delegate_->OnCancelSignin(); - delegate_ = nullptr; + delegate_ = NULL; } return true; } @@ -252,7 +246,7 @@ DCHECK(prompt_for_new_profile_); if (delegate_) { delegate_->OnContinueSignin(); - delegate_ = nullptr; + delegate_ = NULL; } GetWidget()->Close(); }
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h index a466abd..ffa5f579 100644 --- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h +++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_UI_VIEWS_SYNC_PROFILE_SIGNIN_CONFIRMATION_DIALOG_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_SYNC_PROFILE_SIGNIN_CONFIRMATION_DIALOG_VIEWS_H_ -#include <memory> - #include "base/compiler_specific.h" #include "base/macros.h" #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" @@ -25,17 +23,16 @@ public views::ButtonListener { public: // Create and show the dialog, which owns itself. - static void ShowDialog( - Browser* browser, - Profile* profile, - const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); + static void ShowDialog(Browser* browser, + Profile* profile, + const std::string& username, + ui::ProfileSigninConfirmationDelegate* delegate); private: ProfileSigninConfirmationDialogViews( Browser* browser, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate); + ui::ProfileSigninConfirmationDelegate* delegate); ~ProfileSigninConfirmationDialogViews() override; // views::DialogDelegateView: @@ -72,7 +69,7 @@ std::string username_; // Dialog button handler. - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate_; + ui::ProfileSigninConfirmationDelegate* delegate_; // Whether the user should be prompted to create a new profile. bool prompt_for_new_profile_;
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc deleted file mode 100644 index 0837f0e6..0000000 --- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h" - -#include "base/command_line.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/bookmarks/bookmark_model_factory.h" -#include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" -#include "chrome/browser/ui/tab_dialogs.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/test/test_browser_dialog.h" -#include "components/bookmarks/browser/bookmark_model.h" -#include "ui/base/ui_base_switches.h" - -namespace { - -// Test delegate passed to the confirmation dialog to report back the result. -class TestSigninDialogDelegate : public ui::ProfileSigninConfirmationDelegate { - public: - TestSigninDialogDelegate() {} - virtual ~TestSigninDialogDelegate() {} - - void OnCancelSignin() override {} - void OnContinueSignin() override {} - void OnSigninWithNewProfile() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(TestSigninDialogDelegate); -}; - -} // namespace - -class ProfileSigninConfirmationDialogTest : public DialogBrowserTest { - public: - ProfileSigninConfirmationDialogTest() {} - - // content::BrowserTestBase: - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch(switches::kExtendMdToSecondaryUi); - } - - // DialogBrowserTest: - void ShowDialog(const std::string& name) override { - Profile* profile = browser()->profile(); - - // Add a bookmark to ensure CheckShouldPromptForNewProfile() returns true. - bookmarks::BookmarkModel* bookmarks = - BookmarkModelFactory::GetForBrowserContext(profile); - bookmarks->AddURL(bookmarks->bookmark_bar_node(), 0, - base::ASCIIToUTF16("title"), - GURL("http://www.example.com")); - - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - TabDialogs::FromWebContents(web_contents) - ->ShowProfileSigninConfirmation( - browser(), profile, "username@example.com", - base::MakeUnique<TestSigninDialogDelegate>()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationDialogTest); -}; - -// Test that calls ShowDialog("default"). Interactive when run via -// browser_tests --gtest_filter=BrowserDialogTest.Invoke --interactive -// --dialog=ProfileSigninConfirmationDialogTest.InvokeDialog_default -IN_PROC_BROWSER_TEST_F(ProfileSigninConfirmationDialogTest, - InvokeDialog_default) { - RunDialog(); -}
diff --git a/chrome/browser/ui/views/tab_dialogs_views.cc b/chrome/browser/ui/views/tab_dialogs_views.cc index fa36944f..46177c1 100644 --- a/chrome/browser/ui/views/tab_dialogs_views.cc +++ b/chrome/browser/ui/views/tab_dialogs_views.cc
@@ -53,10 +53,10 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) { + ui::ProfileSigninConfirmationDelegate* delegate) { #if !defined(OS_CHROMEOS) - ProfileSigninConfirmationDialogViews::ShowDialog(browser, profile, username, - std::move(delegate)); + ProfileSigninConfirmationDialogViews::ShowDialog( + browser, profile, username, delegate); #else NOTREACHED(); #endif
diff --git a/chrome/browser/ui/views/tab_dialogs_views.h b/chrome/browser/ui/views/tab_dialogs_views.h index c1bc6fc..83f4e473 100644 --- a/chrome/browser/ui/views/tab_dialogs_views.h +++ b/chrome/browser/ui/views/tab_dialogs_views.h
@@ -24,7 +24,7 @@ Browser* browser, Profile* profile, const std::string& username, - std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) override; + ui::ProfileSigninConfirmationDelegate* delegate) override; void ShowManagePasswordsBubble(bool user_action) override; void HideManagePasswordsBubble() override; base::WeakPtr<ValidationMessageBubble> ShowValidationMessage(
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 2049d78..e747aca9 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -357,6 +357,9 @@ ShowError(IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH, false); return; + case policy::EnrollmentStatus::DM_TOKEN_STORE_FAILED: + ShowError(IDS_ENTERPRISE_ENROLLMENT_ERROR_STORE_DM_TOKEN_FAILED, false); + return; } NOTREACHED(); }
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc index d4ffe8ab..9a7197a 100644 --- a/chrome/browser/ui/webui/help/help_handler.cc +++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -50,7 +50,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "ui/base/l10n/l10n_util.h" -#include "v8/include/v8.h" +#include "v8/include/v8-version-string.h" #if defined(OS_CHROMEOS) #include "base/files/file_util_proxy.h" @@ -376,7 +376,7 @@ localized_strings->SetString("productTOS", tos); localized_strings->SetString("jsEngine", "V8"); - localized_strings->SetString("jsEngineVersion", v8::V8::GetVersion()); + localized_strings->SetString("jsEngineVersion", V8_VERSION_STRING); localized_strings->SetString("userAgentInfo", GetUserAgent());
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index 7c3ed61..1962582 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -50,7 +50,7 @@ #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/user_agent.h" #include "ui/base/l10n/l10n_util.h" -#include "v8/include/v8.h" +#include "v8/include/v8-version-string.h" #if defined(OS_CHROMEOS) #include "base/files/file_util_proxy.h" @@ -319,7 +319,7 @@ html_source->AddString("aboutCommandLine", command_line); html_source->AddString("aboutUserAgent", GetUserAgent()); - html_source->AddString("aboutJsEngineVersion", v8::V8::GetVersion()); + html_source->AddString("aboutJsEngineVersion", V8_VERSION_STRING); html_source->AddString("aboutBlinkVersion", content::GetWebKitVersion()); #endif
diff --git a/chrome/browser/ui/webui/signin/OWNERS b/chrome/browser/ui/webui/signin/OWNERS index 568e3fad..4344a30 100644 --- a/chrome/browser/ui/webui/signin/OWNERS +++ b/chrome/browser/ui/webui/signin/OWNERS
@@ -1,4 +1,5 @@ achuith@chromium.org anthonyvd@chromium.org +msarda@chromium.org rogerta@chromium.org xiyuan@chromium.org
diff --git a/chrome/browser/ui/webui/version_ui.cc b/chrome/browser/ui/webui/version_ui.cc index 2b0f6e8c..c3fbfcc4 100644 --- a/chrome/browser/ui/webui/version_ui.cc +++ b/chrome/browser/ui/webui/version_ui.cc
@@ -27,7 +27,7 @@ #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/user_agent.h" #include "ui/base/l10n/l10n_util.h" -#include "v8/include/v8.h" +#include "v8/include/v8-version-string.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" @@ -61,7 +61,7 @@ html_source->AddLocalizedString(version_ui::kPlatform, IDS_PLATFORM_LABEL); html_source->AddString(version_ui::kOSType, version_info::GetOSType()); html_source->AddString(version_ui::kJSEngine, "V8"); - html_source->AddString(version_ui::kJSVersion, v8::V8::GetVersion()); + html_source->AddString(version_ui::kJSVersion, V8_VERSION_STRING); #if defined(OS_ANDROID) html_source->AddString(version_ui::kOSVersion,
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index e34b618..5e1da61 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -677,7 +677,8 @@ mojom("mojo_bindings") { sources = [ - "conflicts/module_event_sink_win.mojom", + "conflicts/module_database_win.mojom", + "conflicts/module_event_win.mojom", "field_trial_recorder.mojom", "net_benchmarking.mojom", "network_diagnostics.mojom",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 62a3c14..6df346e7 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -237,7 +237,7 @@ // Enables or disables flash component updates on Chrome OS. const base::Feature kCrosCompUpdates{"CrosCompUpdates", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; #endif // defined(OS_CHROMEOS) } // namespace features
diff --git a/chrome/common/conflicts/module_database_win.mojom b/chrome/common/conflicts/module_database_win.mojom new file mode 100644 index 0000000..2bce402 --- /dev/null +++ b/chrome/common/conflicts/module_database_win.mojom
@@ -0,0 +1,14 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojom; + +// This brings in a definition for ModuleEvent. +import "chrome/common/conflicts/module_event_win.mojom"; + +// Interface for a remote module database. +interface ModuleDatabase { + // Notifies the module database of a module event in a remote process. + OnModuleEvent(uint32 process_id, ModuleEvent module_event); +};
diff --git a/chrome/common/conflicts/module_event_sink_win.mojom b/chrome/common/conflicts/module_event_sink_win.mojom deleted file mode 100644 index 3d2fa936..0000000 --- a/chrome/common/conflicts/module_event_sink_win.mojom +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module mojom; - -// The types of module events that can occur. -enum ModuleEventType { - // A module was already loaded, but its presence is being observed. - MODULE_ALREADY_LOADED, - // A module is in the process of being loaded. - MODULE_LOADED, - // A module is in the process of being unloaded. - MODULE_UNLOADED, -}; - -// Interface for a remote consumer of module events. -interface ModuleEventSink { - // Notifies the module database of a module event in a remote process. The - // module is identified only by its load address, which is sufficient for - // any process to safely look up the module. - OnModuleEvent(ModuleEventType event_type, uint64 load_address); -};
diff --git a/chrome/common/conflicts/module_event_win.mojom b/chrome/common/conflicts/module_event_win.mojom new file mode 100644 index 0000000..d280156 --- /dev/null +++ b/chrome/common/conflicts/module_event_win.mojom
@@ -0,0 +1,27 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojom; + +// The types of module events that can occur. +enum ModuleEventType { + // A module was already loaded, but its presence is being observed. + MODULE_ALREADY_LOADED, + // A module is in the process of being loaded. + MODULE_LOADED, + // A module is in the process of being unloaded. + MODULE_UNLOADED, +}; + +// A notification about a module being loaded or unloaded. +struct ModuleEvent { + // The type of event. + ModuleEventType event_type; + // The full path to the module being loaded or unloaded. + string module_path; + // The load address of the module. + uint64 load_address; + // The size of the module in memory, in bytes. + uint32 size; +};
diff --git a/chrome/common/conflicts/module_watcher_win.cc b/chrome/common/conflicts/module_watcher_win.cc index fca97a3..424fd13 100644 --- a/chrome/common/conflicts/module_watcher_win.cc +++ b/chrome/common/conflicts/module_watcher_win.cc
@@ -9,11 +9,9 @@ #include <winternl.h> // For UNICODE_STRING. #include <string> -#include <utility> #include "base/lazy_instance.h" #include "base/memory/ptr_util.h" -#include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" #include "base/win/scoped_handle.h" @@ -98,19 +96,22 @@ constexpr char kLdrRegisterDllNotification[] = "LdrRegisterDllNotification"; constexpr char kLdrUnregisterDllNotification[] = "LdrUnregisterDllNotification"; -// Helper function for converting a UNICODE_STRING to a FilePath. -base::FilePath ToFilePath(const UNICODE_STRING* str) { - return base::FilePath( - base::StringPiece16(str->Buffer, str->Length / sizeof(wchar_t))); +// Helper function for converting a UNICODE_STRING to a UTF8 std::string. +std::string ToString(const UNICODE_STRING* str) { + std::string s; + base::WideToUTF8(str->Buffer, str->Length / sizeof(wchar_t), &s); + return s; } template <typename NotificationDataType> void OnModuleEvent(mojom::ModuleEventType event_type, const NotificationDataType& notification_data, const ModuleWatcher::OnModuleEventCallback& callback) { - ModuleWatcher::ModuleEvent event( - event_type, ToFilePath(notification_data.FullDllName), - notification_data.DllBase, notification_data.SizeOfImage); + mojom::ModuleEvent event; + event.event_type = event_type; + event.module_path = ToString(notification_data.FullDllName); + event.load_address = reinterpret_cast<uintptr_t>(notification_data.DllBase); + event.size = notification_data.SizeOfImage; callback.Run(event); } @@ -118,14 +119,14 @@ // static std::unique_ptr<ModuleWatcher> ModuleWatcher::Create( - OnModuleEventCallback callback) { + const OnModuleEventCallback& callback) { // If a ModuleWatcher already exists then bail out. base::AutoLock lock(g_module_watcher_lock.Get()); if (g_module_watcher_instance) return nullptr; // This thread acquired the right to create a ModuleWatcher, so do so. - g_module_watcher_instance = new ModuleWatcher(std::move(callback)); + g_module_watcher_instance = new ModuleWatcher(callback); return base::WrapUnique(g_module_watcher_instance); } @@ -173,11 +174,15 @@ // Walk the module list. MODULEENTRY32 module = {sizeof(module)}; + std::string path; for (BOOL result = ::Module32First(snap.Get(), &module); result != FALSE; result = ::Module32Next(snap.Get(), &module)) { - ModuleEvent event(mojom::ModuleEventType::MODULE_ALREADY_LOADED, - base::FilePath(module.szExePath), module.modBaseAddr, - module.modBaseSize); + base::WideToUTF8(module.szExePath, ::wcslen(module.szExePath), &path); + mojom::ModuleEvent event; + event.event_type = mojom::ModuleEventType::MODULE_ALREADY_LOADED; + event.module_path = path; + event.load_address = reinterpret_cast<uintptr_t>(module.modBaseAddr); + event.size = module.modBaseSize; callback_.Run(event); } @@ -220,8 +225,8 @@ } } -ModuleWatcher::ModuleWatcher(OnModuleEventCallback callback) - : callback_(std::move(callback)) { +ModuleWatcher::ModuleWatcher(const OnModuleEventCallback& callback) + : callback_(callback) { RegisterDllNotificationCallback(); EnumerateAlreadyLoadedModules(); }
diff --git a/chrome/common/conflicts/module_watcher_win.h b/chrome/common/conflicts/module_watcher_win.h index a7c00d1..b2255d0 100644 --- a/chrome/common/conflicts/module_watcher_win.h +++ b/chrome/common/conflicts/module_watcher_win.h
@@ -8,8 +8,7 @@ #include <memory> #include "base/callback.h" -#include "base/files/file_path.h" -#include "chrome/common/conflicts/module_event_sink_win.mojom.h" +#include "chrome/common/conflicts/module_event_win.mojom.h" class ModuleWatcherTest; @@ -23,37 +22,14 @@ // created. class ModuleWatcher { public: - // Houses information about a module load/unload event, and some module - // metadata. - struct ModuleEvent { - ModuleEvent() = default; - ModuleEvent(const ModuleEvent& other) = default; - ModuleEvent(mojom::ModuleEventType event_type, - const base::FilePath& module_path, - void* module_load_address, - size_t module_size) - : event_type(event_type), - module_path(module_path), - module_load_address(module_load_address), - module_size(module_size) {} - - // The type of module event. - mojom::ModuleEventType event_type; - // The full path to the module on disk. - base::FilePath module_path; - // The load address of the module. - void* module_load_address; - // The size of the module in memory. - size_t module_size; - }; - // The type of callback that will be invoked for each module event. This is // invoked by the loader and potentially on any thread. The loader lock is not // held but the execution of this callback blocks the module from being bound. // Keep the amount of work performed here to an absolute minimum. Note that // it is possible for this callback to be invoked after the destruction of the // watcher, but very unlikely. - using OnModuleEventCallback = base::Callback<void(const ModuleEvent& event)>; + using OnModuleEventCallback = + base::Callback<void(const mojom::ModuleEvent& event)>; // Creates and starts a watcher. This enumerates all loaded modules // synchronously on the current thread during construction, and provides @@ -68,7 +44,8 @@ // // Only a single instance of a watcher may exist at any moment. This will // return nullptr when trying to create a second watcher. - static std::unique_ptr<ModuleWatcher> Create(OnModuleEventCallback callback); + static std::unique_ptr<ModuleWatcher> Create( + const OnModuleEventCallback& callback); // This can be called on any thread. After destruction the |callback| // provided to the constructor will no longer be invoked with module events. @@ -106,7 +83,7 @@ private: // Private to enforce Singleton semantics. See Create above. - explicit ModuleWatcher(OnModuleEventCallback callback); + explicit ModuleWatcher(const OnModuleEventCallback& callback); // The current callback. Can end up being invoked on any thread. OnModuleEventCallback callback_;
diff --git a/chrome/common/conflicts/module_watcher_win_unittest.cc b/chrome/common/conflicts/module_watcher_win_unittest.cc index dd698874..02bea081 100644 --- a/chrome/common/conflicts/module_watcher_win_unittest.cc +++ b/chrome/common/conflicts/module_watcher_win_unittest.cc
@@ -10,7 +10,7 @@ #include "testing/gtest/include/gtest/gtest.h" class ModuleWatcherTest : public testing::Test { - protected: + public: ModuleWatcherTest() : module_(nullptr), module_event_count_(0), @@ -18,7 +18,7 @@ module_loaded_event_count_(0), module_unloaded_event_count_(0) {} - void OnModuleEvent(const ModuleWatcher::ModuleEvent& event) { + void OnModuleEvent(const mojom::ModuleEvent& event) { ++module_event_count_; switch (event.event_type) { case mojom::ModuleEventType::MODULE_ALREADY_LOADED: @@ -63,6 +63,7 @@ // Holds a handle to a loaded module. HMODULE module_; + // Total number of module events seen. int module_event_count_; // Total number of MODULE_ALREADY_LOADED events seen.
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index a510af5..51b573d 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1831,6 +1831,10 @@ // Whether the user may exit enrollment. const char kDeviceEnrollmentCanExit[] = "enrollment.can_exit"; +// DM token fetched from the DM server during enrollment. Stored for Active +// Directory devices only. +const char kDeviceDMToken[] = "device_dm_token"; + // How many times HID detection OOBE dialog was shown. const char kTimesHIDDialogShown[] = "HIDDialog.shown_how_many_times";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index f0b812c9..08f7784 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -653,6 +653,7 @@ extern const char kDeviceEnrollmentRequisition[]; extern const char kDeviceEnrollmentAutoStart[]; extern const char kDeviceEnrollmentCanExit[]; +extern const char kDeviceDMToken[]; extern const char kTimesHIDDialogShown[]; extern const char kUsersLRUInputMethod[]; extern const char kEchoCheckedOffers[];
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc index 6098916..633e8e0a 100644 --- a/chrome/install_static/install_util.cc +++ b/chrome/install_static/install_util.cc
@@ -35,6 +35,8 @@ const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; const wchar_t kCrashpadHandler[] = L"crashpad-handler"; +const wchar_t kFallbackHandler[] = L"fallback-handler"; + const wchar_t kProcessType[] = L"type"; const wchar_t kUserDataDirSwitch[] = L"user-data-dir"; const wchar_t kUtilityProcess[] = L"utility";
diff --git a/chrome/install_static/install_util.h b/chrome/install_static/install_util.h index 17c11b7f..7283967 100644 --- a/chrome/install_static/install_util.h +++ b/chrome/install_static/install_util.h
@@ -43,6 +43,7 @@ // https://crbug.com/604923 // Unify these constants with those defined in content_switches.h. extern const wchar_t kCrashpadHandler[]; +extern const wchar_t kFallbackHandler[]; extern const wchar_t kProcessType[]; extern const wchar_t kUserDataDirSwitch[]; extern const wchar_t kUtilityProcess[];
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn index 65df57c..84be262 100644 --- a/chrome/installer/mini_installer/BUILD.gn +++ b/chrome/installer/mini_installer/BUILD.gn
@@ -239,12 +239,15 @@ ] ldflags = [ - "/ENTRY:MainEntryPoint", "/FIXED:NO", "/ignore:4199", "/NXCOMPAT", ] + if (!is_asan) { + ldflags += [ "/ENTRY:MainEntryPoint" ] + } + libs = [ "setupapi.lib" ] deps = [
diff --git a/chrome/installer/mini_installer/mini_installer.cc b/chrome/installer/mini_installer/mini_installer.cc index 7ca6e9f1..be29092fd 100644 --- a/chrome/installer/mini_installer/mini_installer.cc +++ b/chrome/installer/mini_installer/mini_installer.cc
@@ -15,7 +15,7 @@ // BufferSecurityCheck="false" compiler: /GS- // EntryPointSymbol="MainEntryPoint" linker: /ENTRY // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB -// OptimizeForWindows98="1" liker: /OPT:NOWIN98 +// OptimizeForWindows98="1" linker: /OPT:NOWIN98 // linker: /SAFESEH:NO // have the linker merge the sections, saving us ~500 bytes. @@ -895,6 +895,19 @@ ::ExitProcess(result.exit_code); } +#if defined(ADDRESS_SANITIZER) +// Executables instrumented with ASAN need CRT functions. We do not use +// the /ENTRY switch for ASAN instrumented executable and a "main" function +// is required. +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) { + MainEntryPoint(); + return 0; +} +#endif + // VC Express editions don't come with the memset CRT obj file and linking to // the obj files between versions becomes a bit problematic. Therefore, // simply implement memset.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index d5d16ed..cfaf9d82 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2119,7 +2119,6 @@ "../browser/ui/views/frame/browser_non_client_frame_view_browsertest_win.cc", "../browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc", "../browser/ui/views/select_file_dialog_extension_browsertest.cc", - "../browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc", ] deps += [ "//ui/views" ] if (!is_chromeos && (!is_mac || mac_views_browser)) { @@ -2350,7 +2349,6 @@ "../browser/service_process/service_process_control_browsertest.cc", # inline login UI is disabled on chromeos - "../browser/ui/views/sync/profile_signin_confirmation_dialog_views_browsertest.cc", "../browser/ui/webui/signin/inline_login_ui_browsertest.cc", # chromeos does not use the desktop user manager @@ -3096,8 +3094,6 @@ "../browser/component_updater/subresource_filter_component_installer_unittest.cc", "../browser/component_updater/supervised_user_whitelist_installer_unittest.cc", "../browser/component_updater/sw_reporter_installer_win_unittest.cc", - "../browser/conflicts/module_database_win_unittest.cc", - "../browser/conflicts/module_event_sink_impl_win_unittest.cc", "../browser/content_settings/content_settings_default_provider_unittest.cc", "../browser/content_settings/content_settings_mock_observer.cc", "../browser/content_settings/content_settings_mock_observer.h",
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 61182fe..d2a931c 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -645,7 +645,7 @@ Refresh(); } -void PersonalDataManager::UpdateServerCardBillingAddress( +void PersonalDataManager::UpdateServerCardMetadata( const CreditCard& credit_card) { DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h index 239c88d6..165862f 100644 --- a/components/autofill/core/browser/personal_data_manager.h +++ b/components/autofill/core/browser/personal_data_manager.h
@@ -152,9 +152,9 @@ // status can be changed. Looks up the card by server ID. virtual void UpdateServerCreditCard(const CreditCard& credit_card); - // Updates the billing address for the server |credit_card|. Looks up the card - // by GUID. - void UpdateServerCardBillingAddress(const CreditCard& credit_card); + // Updates the use stats and billing address id for the server |credit_card|. + // Looks up the card by server_id. + void UpdateServerCardMetadata(const CreditCard& credit_card); // Resets the card for |guid| to the masked state. void ResetFullServerCard(const std::string& guid);
diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn index 23255030..0cf0c6ca 100644 --- a/components/crash/content/app/BUILD.gn +++ b/components/crash/content/app/BUILD.gn
@@ -70,12 +70,15 @@ "fallback_crash_handler_launcher_win.h", "fallback_crash_handler_win.cc", "fallback_crash_handler_win.h", + "fallback_crash_handling_win.cc", + "fallback_crash_handling_win.h", "run_as_crashpad_handler_win.cc", "run_as_crashpad_handler_win.h", ] deps = [ "//base", + "//chrome/install_static:install_static_util", "//third_party/crashpad/crashpad/client", "//third_party/crashpad/crashpad/handler:handler_lib", "//third_party/crashpad/crashpad/minidump", @@ -221,6 +224,7 @@ "crash_keys_win_unittest.cc", "fallback_crash_handler_launcher_win_unittest.cc", "fallback_crash_handler_win_unittest.cc", + "fallback_crash_handling_win_unittest.cc", ] deps = [ ":lib",
diff --git a/components/crash/content/app/fallback_crash_handler_launcher_win.cc b/components/crash/content/app/fallback_crash_handler_launcher_win.cc index 1fa0603..45c8c83 100644 --- a/components/crash/content/app/fallback_crash_handler_launcher_win.cc +++ b/components/crash/content/app/fallback_crash_handler_launcher_win.cc
@@ -28,8 +28,8 @@ const base::CommandLine& program, const base::FilePath& crashpad_database) { // Open an inheritable handle to self. This will be inherited to the handler. - const DWORD kAccessMask = - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE; + const DWORD kAccessMask = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | + PROCESS_DUP_HANDLE | PROCESS_TERMINATE; self_process_handle_.Set( OpenProcess(kAccessMask, TRUE, ::GetCurrentProcessId())); if (!self_process_handle_.IsValid())
diff --git a/components/crash/content/app/fallback_crash_handler_win.cc b/components/crash/content/app/fallback_crash_handler_win.cc index 13b89d4..c17849429 100644 --- a/components/crash/content/app/fallback_crash_handler_win.cc +++ b/components/crash/content/app/fallback_crash_handler_win.cc
@@ -161,23 +161,30 @@ // Write the key/value pairs and collect their locations. std::vector<crashpad::MinidumpSimpleStringDictionaryEntry> entries; for (const auto& kv : crash_keys) { + // The key of a key/value pair should never be empty. + DCHECK(!kv.first.empty()); + crashpad::MinidumpSimpleStringDictionaryEntry entry = {0}; - entry.key = next_available_byte; - uint32_t key_len = base::saturated_cast<uint32_t>(kv.first.size()); - if (!WriteAndAdvance(&key_len, sizeof(key_len), &next_available_byte) || - !WriteAndAdvance(&kv.first[0], key_len, &next_available_byte)) { - return false; - } + // Skip this key/value if the value is empty. + if (!kv.second.empty()) { + entry.key = next_available_byte; + uint32_t key_len = base::saturated_cast<uint32_t>(kv.first.size()); + if (!WriteAndAdvance(&key_len, sizeof(key_len), &next_available_byte) || + !WriteAndAdvance(&kv.first[0], key_len, &next_available_byte)) { + return false; + } - entry.value = next_available_byte; - uint32_t value_len = base::saturated_cast<uint32_t>(kv.second.size()); - if (!WriteAndAdvance(&value_len, sizeof(value_len), &next_available_byte) || - !WriteAndAdvance(&kv.second[0], value_len, &next_available_byte)) { - return false; - } + entry.value = next_available_byte; + uint32_t value_len = base::saturated_cast<uint32_t>(kv.second.size()); + if (!WriteAndAdvance(&value_len, sizeof(value_len), + &next_available_byte) || + !WriteAndAdvance(&kv.second[0], value_len, &next_available_byte)) { + return false; + } - entries.push_back(entry); + entries.push_back(entry); + } } // Write the dictionary array itself - note the array is count-prefixed. @@ -340,10 +347,11 @@ return false; // Retrieve the thread id argument. - unsigned thread_id = 0; + unsigned int thread_id = 0; if (!base::StringToUint(cmd_line.GetSwitchValueASCII("thread"), &thread_id)) { return false; } + thread_id_ = thread_id; // Retrieve the "exception-pointers" argument. uint64_t uint_exc_ptrs = 0;
diff --git a/components/crash/content/app/fallback_crash_handler_win.h b/components/crash/content/app/fallback_crash_handler_win.h index d9e96bb..579bcb5 100644 --- a/components/crash/content/app/fallback_crash_handler_win.h +++ b/components/crash/content/app/fallback_crash_handler_win.h
@@ -45,6 +45,8 @@ const std::string& channel, const std::string& process_type); + const base::Process& process() const { return process_; } + private: base::Process process_; base::PlatformThreadId thread_id_;
diff --git a/components/crash/content/app/fallback_crash_handling_win.cc b/components/crash/content/app/fallback_crash_handling_win.cc new file mode 100644 index 0000000..e83be627 --- /dev/null +++ b/components/crash/content/app/fallback_crash_handling_win.cc
@@ -0,0 +1,119 @@ +// 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 "components/crash/content/app/fallback_crash_handling_win.h" + +#include <memory> + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "components/crash/content/app/crash_switches.h" +#include "components/crash/content/app/fallback_crash_handler_launcher_win.h" +#include "components/crash/content/app/fallback_crash_handler_win.h" + +namespace crash_reporter { + +namespace switches { +const char kFallbackCrashHandler[] = "fallback-handler"; +const char kPrefetchArgument[] = "/prefetch:7"; +} + +const uint32_t kFallbackCrashTerminationCode = 0xFFFF8001; + +namespace { + +std::unique_ptr<FallbackCrashHandlerLauncher> g_fallback_crash_handler_launcher; + +LONG WINAPI FallbackUnhandledExceptionFilter(EXCEPTION_POINTERS* exc_ptrs) { + if (!g_fallback_crash_handler_launcher) + return EXCEPTION_CONTINUE_SEARCH; + + return g_fallback_crash_handler_launcher->LaunchAndWaitForHandler(exc_ptrs); +} + +} // namespace + +bool SetupFallbackCrashHandling(const base::CommandLine& command_line) { + DCHECK(!g_fallback_crash_handler_launcher); + + // Run the same program. + base::CommandLine base_command_line(command_line.GetProgram()); + base_command_line.AppendSwitchASCII("type", switches::kFallbackCrashHandler); + + // This is to support testing under gtest. + if (command_line.HasSwitch(::switches::kTestChildProcess)) { + base_command_line.AppendSwitchASCII( + ::switches::kTestChildProcess, + command_line.GetSwitchValueASCII(::switches::kTestChildProcess)); + } + + // All Chrome processes need a prefetch argument. + base_command_line.AppendArg(switches::kPrefetchArgument); + + // Get the database path. + base::FilePath database_path = command_line.GetSwitchValuePath("database"); + if (database_path.empty()) { + NOTREACHED(); + return false; + } + + std::unique_ptr<FallbackCrashHandlerLauncher> fallback_launcher( + new FallbackCrashHandlerLauncher()); + + if (!fallback_launcher->Initialize(base_command_line, database_path)) { + NOTREACHED(); + return false; + } + + // This is necessary because chrome_elf stubs out the + // SetUnhandledExceptionFilter in the IAT of chrome.exe. + typedef PTOP_LEVEL_EXCEPTION_FILTER(WINAPI * + SetUnhandledExceptionFilterFunction)( + PTOP_LEVEL_EXCEPTION_FILTER filter); + HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); + if (!kernel32) + return false; + + SetUnhandledExceptionFilterFunction set_unhandled_exception_filter = + reinterpret_cast<SetUnhandledExceptionFilterFunction>( + GetProcAddress(kernel32, "SetUnhandledExceptionFilter")); + if (!set_unhandled_exception_filter) + return false; + + // Success, pass ownership to the global. + g_fallback_crash_handler_launcher = std::move(fallback_launcher); + + set_unhandled_exception_filter(&FallbackUnhandledExceptionFilter); + + return true; +} + +int RunAsFallbackCrashHandler(const base::CommandLine& command_line, + std::string product_name, + std::string version, + std::string channel_name) { + FallbackCrashHandler fallback_handler; + + if (!fallback_handler.ParseCommandLine(command_line)) { + // TODO(siggi): Figure out how to UMA from this process, if need be. + return 1; + } + + if (!fallback_handler.GenerateCrashDump( + product_name, version, channel_name, + crash_reporter::switches::kCrashpadHandler)) { + // TODO(siggi): Figure out how to UMA from this process, if need be. + return 2; + } + + if (!fallback_handler.process().Terminate(kFallbackCrashTerminationCode, + false)) { + return 3; + } + + return 0; +} + +} // namespace crash_reporter
diff --git a/components/crash/content/app/fallback_crash_handling_win.h b/components/crash/content/app/fallback_crash_handling_win.h new file mode 100644 index 0000000..ebf5d9f --- /dev/null +++ b/components/crash/content/app/fallback_crash_handling_win.h
@@ -0,0 +1,43 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLING_WIN_H_ +#define COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLING_WIN_H_ + +#include <stdint.h> +#include <string> + +#include "base/command_line.h" + +namespace crash_reporter { + +namespace switches { +extern const char kFallbackCrashHandler[]; +// The fallback handler uses the same prefetch ID as the Crashpad handler. +extern const char kPrefetchArgument[]; +} + +// A somewhat unique exit code for the crashed process. This is mostly +// for testing, as there won't likely be anyone around to record the exit +// code of the Crashpad handler. +extern const uint32_t kFallbackCrashTerminationCode; + +// Sets up fallback crash handling for this process. +// Note that this installs an unhandled exception filter, and requires +// that the executable call the "RunAsFallbackCrashHandler" function, when +// it's passed a --type switch with the value |kFallbackCrashHandlerType|. +bool SetupFallbackCrashHandling(const base::CommandLine& command_line); + +// Runs the fallback crash handler process, to handle a crash in a process +// that's previously called SetupFallbackCrashHandling. +// The |product_name|, |version| and |channel_name| parameters will be used +// as properties of the crash for the purposes of upload. +int RunAsFallbackCrashHandler(const base::CommandLine& command_line, + std::string product_name, + std::string version, + std::string channel_name); + +} // namespace crash_reporter + +#endif // COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLING_WIN_H_
diff --git a/components/crash/content/app/fallback_crash_handling_win_unittest.cc b/components/crash/content/app/fallback_crash_handling_win_unittest.cc new file mode 100644 index 0000000..7df6b20 --- /dev/null +++ b/components/crash/content/app/fallback_crash_handling_win_unittest.cc
@@ -0,0 +1,85 @@ +// 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 "components/crash/content/app/fallback_crash_handling_win.h" + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/logging.h" +#include "base/test/multiprocess_test.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/multiprocess_func_list.h" +#include "third_party/crashpad/crashpad/client/crash_report_database.h" + +namespace crash_reporter { + +namespace { + +const DWORD kExceptionCode = 0xCAFEBABE; + +// This main function runs in two modes, first as a faux-crashpad handler, +// and then with --type=fallback-handler to handle the crash in the first +// instance. +MULTIPROCESS_TEST_MAIN(FallbackCrashHandlingWinRunHandler) { + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->GetSwitchValueASCII("type") == + switches::kFallbackCrashHandler) { + return RunAsFallbackCrashHandler(*cmd_line, + "FallbackCrashHandlingWinRunHandler", + "1.2.3.4", "FakeChannel"); + } + + CHECK(SetupFallbackCrashHandling(*cmd_line)); + + // Provoke a crash with a well-defined exception code. + // The process shouldn't terminate with this exception code. + RaiseException(kExceptionCode, 0, 0, nullptr); + + // This process should never return from the exception. + CHECK(false) << "Unexpected return from RaiseException"; + + // Should never get here. + return 0; +} + +class FallbackCrashHandlingTest : public base::MultiProcessTest { + public: + void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); } + + protected: + base::ScopedTempDir database_dir_; +}; + +} // namespace + +TEST_F(FallbackCrashHandlingTest, SetupAndRunAsFallbackCrashHandler) { + // Launch a subprocess to test the fallback handling implementation. + base::CommandLine cmd_line = base::GetMultiProcessTestChildBaseCommandLine(); + cmd_line.AppendSwitchPath("database", database_dir_.GetPath()); + + base::LaunchOptions options; + options.start_hidden = true; + base::Process test_child = base::SpawnMultiProcessTestChild( + "FallbackCrashHandlingWinRunHandler", cmd_line, options); + + ASSERT_TRUE(test_child.IsValid()); + int exit_code = -1; + ASSERT_TRUE(test_child.WaitForExit(&exit_code)); + ASSERT_EQ(kFallbackCrashTerminationCode, static_cast<uint32_t>(exit_code)); + + // Validate that the database contains one valid crash dump. + std::unique_ptr<crashpad::CrashReportDatabase> database = + crashpad::CrashReportDatabase::InitializeWithoutCreating( + database_dir_.GetPath()); + + std::vector<crashpad::CrashReportDatabase::Report> reports; + ASSERT_EQ(crashpad::CrashReportDatabase::kNoError, + database->GetPendingReports(&reports)); + + EXPECT_EQ(1U, reports.size()); +} + +} // namespace crash_reporter
diff --git a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc index e900dab2..147cfdb 100644 --- a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc +++ b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -99,7 +99,7 @@ const ImageFetchedCallback& callback) { ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); base::StringPiece raw_data = resource_bundle.GetRawDataResourceForScale( - IDR_PHYSICAL_WEB_LOGO, resource_bundle.GetMaxScaleFactor()); + IDR_PHYSICAL_WEB_LOGO_WITH_PADDING, resource_bundle.GetMaxScaleFactor()); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(callback,
diff --git a/components/password_manager/core/browser/password_reuse_detector.cc b/components/password_manager/core/browser/password_reuse_detector.cc index 625994a..dd9b2a9 100644 --- a/components/password_manager/core/browser/password_reuse_detector.cc +++ b/components/password_manager/core/browser/password_reuse_detector.cc
@@ -4,6 +4,8 @@ #include "components/password_manager/core/browser/password_reuse_detector.h" +#include <algorithm> + #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/password_reuse_detector_consumer.h" #include "components/password_manager/core/browser/psl_matching_helper.h" @@ -15,6 +17,22 @@ // It does not make sense to consider short strings for password reuse, since it // is quite likely that they are parts of common words. constexpr size_t kMinPasswordLengthToCheck = 8; + +// Returns true iff |suffix_candidate| is a suffix of |str|. +bool IsSuffix(const base::string16& str, + const base::string16& suffix_candidate) { + if (str.size() < suffix_candidate.size()) + return false; + return std::equal(suffix_candidate.rbegin(), suffix_candidate.rend(), + str.rbegin()); +} + +} // namespace + +bool ReverseStringLess::operator()(const base::string16& lhs, + const base::string16& rhs) const { + return std::lexicographical_compare(lhs.rbegin(), lhs.rend(), rhs.rbegin(), + rhs.rend()); } PasswordReuseDetector::PasswordReuseDetector() {} @@ -40,40 +58,62 @@ const base::string16& input, const std::string& domain, PasswordReuseDetectorConsumer* consumer) { - // TODO(crbug.com/668155): Optimize password look-up. DCHECK(consumer); + if (input.size() < kMinPasswordLengthToCheck) + return; + const std::string registry_controlled_domain = GetRegistryControlledDomain(GURL(domain)); - for (size_t i = 0; i + kMinPasswordLengthToCheck <= input.size(); ++i) { - const base::string16 input_suffix = input.substr(i); - auto passwords_it = passwords_.find(input_suffix); - if (passwords_it == passwords_.end()) - continue; + auto passwords_iterator = FindSavedPassword(input); + if (passwords_iterator == passwords_.end()) + return; - // Password found, check whether it's saved on the same domain. - const std::set<std::string>& domains = passwords_it->second; - DCHECK(!domains.empty()); - if (domains.find(registry_controlled_domain) == domains.end()) { - // Return only one domain. - const std::string& saved_domain = *domains.begin(); - consumer->OnReuseFound(input_suffix, saved_domain, saved_passwords_, - domains.size()); - return; - } + const std::set<std::string>& domains = passwords_iterator->second; + DCHECK(!domains.empty()); + if (domains.find(registry_controlled_domain) == domains.end()) { + // Return only one domain. + const std::string& saved_domain = *domains.begin(); + consumer->OnReuseFound(passwords_iterator->first, saved_domain, + saved_passwords_, domains.size()); + return; } } void PasswordReuseDetector::AddPassword(const autofill::PasswordForm& form) { - const base::string16& password = form.password_value; - if (password.size() < kMinPasswordLengthToCheck) + if (form.password_value.size() < kMinPasswordLengthToCheck) return; GURL signon_realm(form.signon_realm); const std::string domain = GetRegistryControlledDomain(signon_realm); - std::set<std::string>& domains = passwords_[password]; + std::set<std::string>& domains = passwords_[form.password_value]; if (domains.find(domain) == domains.end()) { ++saved_passwords_; domains.insert(domain); } } +PasswordReuseDetector::passwords_iterator +PasswordReuseDetector::FindSavedPassword(const base::string16& input) { + // Keys in |passwords_| are ordered by lexicographical order of reversed + // strings. In order to check a password reuse a key of |passwords_| that is a + // suffix of |input| should be found. The longest such key should be the + // largest key in the |passwords_| keys order that is equal or smaller to + // |input|. + if (passwords_.empty()) + return passwords_.end(); + + // lower_bound returns the first key that is bigger or equal to input. + auto it = passwords_.lower_bound(input); + if (it != passwords_.end() && it->first == input) { + // If the key is equal then a saved password is found. + return it; + } + + // Otherwise the previous key is a candidate for password reuse. + if (it == passwords_.begin()) + return passwords_.end(); + + --it; + return IsSuffix(input, it->first) ? it : passwords_.end(); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_reuse_detector.h b/components/password_manager/core/browser/password_reuse_detector.h index 38151de4..967c941a 100644 --- a/components/password_manager/core/browser/password_reuse_detector.h +++ b/components/password_manager/core/browser/password_reuse_detector.h
@@ -20,6 +20,11 @@ class PasswordReuseDetectorConsumer; +// Comparator that compares reversed strings. +struct ReverseStringLess { + bool operator()(const base::string16& lhs, const base::string16& rhs) const; +}; + // Per-profile class responsible for detection of password reuse, i.e. that the // user input on some site contains the password saved on another site. // It receives saved passwords through PasswordStoreConsumer interface. @@ -47,14 +52,23 @@ PasswordReuseDetectorConsumer* consumer); private: + using passwords_iterator = std::map<base::string16, + std::set<std::string>, + ReverseStringLess>::const_iterator; + // Add password from |form| to |passwords_|. void AddPassword(const autofill::PasswordForm& form); + // Returns the iterator to |passwords_| that corresponds to the longest key in + // |passwords_| that is a suffix of |input|. Returns passwords_.end() in case + // when no key in |passwords_| is a prefix of |input|. + passwords_iterator FindSavedPassword(const base::string16& input); + // Contains all passwords. // A key is a password. // A value is a set of registry controlled domains on which the password // saved. - std::map<base::string16, std::set<std::string>> passwords_; + std::map<base::string16, std::set<std::string>, ReverseStringLess> passwords_; // Number of passwords in |passwords_|, each password is calculated the number // of times how many different sites it's saved on.
diff --git a/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/components/password_manager/core/browser/password_reuse_detector_unittest.cc index 7e8331e..dac4dd6 100644 --- a/components/password_manager/core/browser/password_reuse_detector_unittest.cc +++ b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -22,21 +22,30 @@ namespace { -std::vector<std::unique_ptr<PasswordForm>> GetSavedForms() { - std::vector<std::unique_ptr<PasswordForm>> result; - std::vector<std::pair<std::string, std::string>> domains_passwords = { +std::vector<std::pair<std::string, std::string>> GetTestDomainsPasswords() { + return { {"https://accounts.google.com", "password"}, {"https://facebook.com", "123456789"}, {"https://a.appspot.com", "abcdefghi"}, {"https://twitter.com", "short"}, + {"https://example1.com", "secretword"}, + {"https://example2.com", "secretword"}, }; +} - for (const auto& domain_password : domains_passwords) { - std::unique_ptr<PasswordForm> form(new PasswordForm); - form->signon_realm = domain_password.first; - form->password_value = ASCIIToUTF16(domain_password.second); - result.push_back(std::move(form)); - } +std::unique_ptr<PasswordForm> GetForm( + const std::pair<std::string, std::string>& domain_password) { + std::unique_ptr<PasswordForm> form(new PasswordForm); + form->signon_realm = domain_password.first; + form->password_value = ASCIIToUTF16(domain_password.second); + return form; +} + +std::vector<std::unique_ptr<PasswordForm>> GetForms( + const std::vector<std::pair<std::string, std::string>>& domains_passwords) { + std::vector<std::unique_ptr<PasswordForm>> result; + for (const auto& domain_password : domains_passwords) + result.push_back(GetForm(domain_password)); return result; } @@ -52,7 +61,7 @@ TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) { PasswordReuseDetector reuse_detector; - reuse_detector.OnGetPasswordStoreResults(GetSavedForms()); + reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords())); MockPasswordReuseDetectorConsumer mockConsumer; EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); @@ -63,14 +72,27 @@ testing::Mock::VerifyAndClearExpectations(&mockConsumer); EXPECT_CALL(mockConsumer, - OnReuseFound(ASCIIToUTF16("password"), "google.com", 3, 1)); + OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1)); reuse_detector.CheckReuse(ASCIIToUTF16("123password"), "https://evil.com", &mockConsumer); + testing::Mock::VerifyAndClearExpectations(&mockConsumer); + + EXPECT_CALL(mockConsumer, + OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1)); + reuse_detector.CheckReuse(ASCIIToUTF16("password"), "https://evil.com", + &mockConsumer); + + testing::Mock::VerifyAndClearExpectations(&mockConsumer); + + EXPECT_CALL(mockConsumer, + OnReuseFound(ASCIIToUTF16("secretword"), "example1.com", 5, 2)); + reuse_detector.CheckReuse(ASCIIToUTF16("abcdsecretword"), "https://evil.com", + &mockConsumer); } TEST(PasswordReuseDetectorTest, PSLMatchNoReuseEvent) { PasswordReuseDetector reuse_detector; - reuse_detector.OnGetPasswordStoreResults(GetSavedForms()); + reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords())); MockPasswordReuseDetectorConsumer mockConsumer; EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); @@ -80,20 +102,20 @@ TEST(PasswordReuseDetectorTest, NoPSLMatchReuseEvent) { PasswordReuseDetector reuse_detector; - reuse_detector.OnGetPasswordStoreResults(GetSavedForms()); + reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords())); MockPasswordReuseDetectorConsumer mockConsumer; // a.appspot.com and b.appspot.com are not PSL matches. So reuse event should // be raised. EXPECT_CALL(mockConsumer, - OnReuseFound(ASCIIToUTF16("abcdefghi"), "a.appspot.com", 3, 1)); + OnReuseFound(ASCIIToUTF16("abcdefghi"), "a.appspot.com", 5, 1)); reuse_detector.CheckReuse(ASCIIToUTF16("abcdefghi"), "https://b.appspot.com", &mockConsumer); } TEST(PasswordReuseDetectorTest, TooShortPasswordNoReuseEvent) { PasswordReuseDetector reuse_detector; - reuse_detector.OnGetPasswordStoreResults(GetSavedForms()); + reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords())); MockPasswordReuseDetectorConsumer mockConsumer; EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); @@ -102,7 +124,7 @@ TEST(PasswordReuseDetectorTest, PasswordNotInputSuffixNoReuseEvent) { PasswordReuseDetector reuse_detector; - reuse_detector.OnGetPasswordStoreResults(GetSavedForms()); + reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords())); MockPasswordReuseDetectorConsumer mockConsumer; EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); @@ -117,7 +139,8 @@ {PasswordStoreChange::ADD, PasswordStoreChange::UPDATE, PasswordStoreChange::REMOVE}) { PasswordReuseDetector reuse_detector; - PasswordStoreChangeList changes = GetChangeList(type, GetSavedForms()); + PasswordStoreChangeList changes = + GetChangeList(type, GetForms(GetTestDomainsPasswords())); reuse_detector.OnLoginsChanged(changes); MockPasswordReuseDetectorConsumer mockConsumer; @@ -125,13 +148,42 @@ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); } else { EXPECT_CALL(mockConsumer, - OnReuseFound(ASCIIToUTF16("password"), "google.com", 3, 1)); + OnReuseFound(ASCIIToUTF16("password"), "google.com", 5, 1)); } reuse_detector.CheckReuse(ASCIIToUTF16("123password"), "https://evil.com", &mockConsumer); } } +TEST(PasswordReuseDetectorTest, CheckLongestPasswordMatchReturn) { + const std::vector<std::pair<std::string, std::string>> domain_passwords = { + {"https://example1.com", "234567890"}, + {"https://example2.com", "01234567890"}, + {"https://example3.com", "1234567890"}, + }; + + PasswordReuseDetector reuse_detector; + reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords)); + + MockPasswordReuseDetectorConsumer mockConsumer; + + EXPECT_CALL(mockConsumer, + OnReuseFound(ASCIIToUTF16("01234567890"), "example2.com", 3, 1)); + reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com", + &mockConsumer); + testing::Mock::VerifyAndClearExpectations(&mockConsumer); + + EXPECT_CALL(mockConsumer, + OnReuseFound(ASCIIToUTF16("1234567890"), "example3.com", 3, 1)); + reuse_detector.CheckReuse(ASCIIToUTF16("1234567890"), "https://evil.com", + &mockConsumer); + testing::Mock::VerifyAndClearExpectations(&mockConsumer); + + EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0); + reuse_detector.CheckReuse(ASCIIToUTF16("34567890"), "https://evil.com", + &mockConsumer); +} + } // namespace } // namespace password_manager
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h index 5c468a6e..b61fe35 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.h +++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -227,6 +227,8 @@ kMetricEnrollmentNoDeviceIdentification = 54, // Active Directory policy fetch failed. kMetricEnrollmentActiveDirectoryPolicyFetchFailed = 55, + // Failed to store DM token into the local state. + kMetricEnrollmentStoreDMTokenFailed = 56, }; // Events related to policy refresh.
diff --git a/components/reading_list/ios/reading_list_entry.h b/components/reading_list/ios/reading_list_entry.h index e454850..17651cbed 100644 --- a/components/reading_list/ios/reading_list_entry.h +++ b/components/reading_list/ios/reading_list_entry.h
@@ -15,6 +15,13 @@ namespace reading_list { class ReadingListLocal; + +// The different ways a reading list entry is added. +// |ADDED_VIA_CURRENT_APP| is when the entry was added by the user from within +// the current instance of the app. +// |ADDED_VIA_EXTENSION| is when the entry was added via the share extension. +// |ADDED_VIA_SYNC| is when the entry was added with sync. +enum EntrySource { ADDED_VIA_CURRENT_APP, ADDED_VIA_EXTENSION, ADDED_VIA_SYNC }; } namespace sync_pb {
diff --git a/components/reading_list/ios/reading_list_model.h b/components/reading_list/ios/reading_list_model.h index 73968eea..5a95d7a 100644 --- a/components/reading_list/ios/reading_list_model.h +++ b/components/reading_list/ios/reading_list_model.h
@@ -93,8 +93,10 @@ // trimmed copy of |title. // The addition may be asynchronous, and the data will be available only once // the observers are notified. - virtual const ReadingListEntry& AddEntry(const GURL& url, - const std::string& title) = 0; + virtual const ReadingListEntry& AddEntry( + const GURL& url, + const std::string& title, + reading_list::EntrySource source) = 0; // Removes an entry. The removal may be asynchronous, and not happen // immediately.
diff --git a/components/reading_list/ios/reading_list_model_bridge_observer.h b/components/reading_list/ios/reading_list_model_bridge_observer.h index 5cb33183..f19e09e 100644 --- a/components/reading_list/ios/reading_list_model_bridge_observer.h +++ b/components/reading_list/ios/reading_list_model_bridge_observer.h
@@ -30,7 +30,8 @@ willAddEntry:(const ReadingListEntry&)entry; - (void)readingListModel:(const ReadingListModel*)model - didAddEntry:(const GURL&)url; + didAddEntry:(const GURL&)url + entrySource:(reading_list::EntrySource)source; - (void)readingListModelBeganBatchUpdates:(const ReadingListModel*)model; - (void)readingListModelCompletedBatchUpdates:(const ReadingListModel*)model; @@ -65,7 +66,8 @@ void ReadingListWillAddEntry(const ReadingListModel* model, const ReadingListEntry& entry) override; void ReadingListDidAddEntry(const ReadingListModel* model, - const GURL& url) override; + const GURL& url, + reading_list::EntrySource source) override; void ReadingListDidApplyChanges(ReadingListModel* model) override; void ReadingListWillUpdateEntry(const ReadingListModel* model, const GURL& url) override;
diff --git a/components/reading_list/ios/reading_list_model_bridge_observer.mm b/components/reading_list/ios/reading_list_model_bridge_observer.mm index efe4ddd9..3595d38 100644 --- a/components/reading_list/ios/reading_list_model_bridge_observer.mm +++ b/components/reading_list/ios/reading_list_model_bridge_observer.mm
@@ -54,9 +54,12 @@ void ReadingListModelBridge::ReadingListDidAddEntry( const ReadingListModel* model, - const GURL& url) { - if ([observer_ respondsToSelector:@selector(readingListModel:didAddEntry:)]) { - [observer_ readingListModel:model didAddEntry:url]; + const GURL& url, + reading_list::EntrySource source) { + if ([observer_ respondsToSelector:@selector(readingListModel: + didAddEntry: + entrySource:)]) { + [observer_ readingListModel:model didAddEntry:url entrySource:source]; } }
diff --git a/components/reading_list/ios/reading_list_model_impl.cc b/components/reading_list/ios/reading_list_model_impl.cc index acb08106..cf7ee6b 100644 --- a/components/reading_list/ios/reading_list_model_impl.cc +++ b/components/reading_list/ios/reading_list_model_impl.cc
@@ -242,7 +242,7 @@ GURL url = entry->URL(); entries_->insert(std::make_pair(url, std::move(*entry))); for (auto& observer : observers_) { - observer.ReadingListDidAddEntry(this, url); + observer.ReadingListDidAddEntry(this, url, reading_list::ADDED_VIA_SYNC); observer.ReadingListDidApplyChanges(this); } } @@ -306,7 +306,8 @@ const ReadingListEntry& ReadingListModelImpl::AddEntry( const GURL& url, - const std::string& title) { + const std::string& title, + reading_list::EntrySource source) { DCHECK(CalledOnValidThread()); DCHECK(loaded()); DCHECK(url.SchemeIsHTTPOrHTTPS()); @@ -327,7 +328,7 @@ } for (auto& observer : observers_) { - observer.ReadingListDidAddEntry(this, url); + observer.ReadingListDidAddEntry(this, url, source); observer.ReadingListDidApplyChanges(this); }
diff --git a/components/reading_list/ios/reading_list_model_impl.h b/components/reading_list/ios/reading_list_model_impl.h index 8d31540..1b6f9a2 100644 --- a/components/reading_list/ios/reading_list_model_impl.h +++ b/components/reading_list/ios/reading_list_model_impl.h
@@ -60,7 +60,8 @@ void RemoveEntryByURL(const GURL& url) override; const ReadingListEntry& AddEntry(const GURL& url, - const std::string& title) override; + const std::string& title, + reading_list::EntrySource source) override; void SetReadStatus(const GURL& url, bool read) override;
diff --git a/components/reading_list/ios/reading_list_model_observer.h b/components/reading_list/ios/reading_list_model_observer.h index fc59569..ffaaed8 100644 --- a/components/reading_list/ios/reading_list_model_observer.h +++ b/components/reading_list/ios/reading_list_model_observer.h
@@ -8,9 +8,10 @@ #include <set> #include <vector> +#include "components/reading_list/ios/reading_list_entry.h" + class GURL; class ReadingListModel; -class ReadingListEntry; // Observer for the Reading List model. In the observer methods care should be // taken to not modify the model. @@ -58,8 +59,10 @@ // Invoked when elements have been added. This method is called after the // the entry has been added to the model and the entry can now be retrieved // from the model. + // |source| says where the entry came from. virtual void ReadingListDidAddEntry(const ReadingListModel* model, - const GURL& url) {} + const GURL& url, + reading_list::EntrySource source) {} // Invoked when an entry is about to change. virtual void ReadingListWillUpdateEntry(const ReadingListModel* model,
diff --git a/components/reading_list/ios/reading_list_model_unittest.mm b/components/reading_list/ios/reading_list_model_unittest.mm index bdcc0084..563c1c3 100644 --- a/components/reading_list/ios/reading_list_model_unittest.mm +++ b/components/reading_list/ios/reading_list_model_unittest.mm
@@ -231,7 +231,8 @@ observer_add_ += 1; } void ReadingListDidAddEntry(const ReadingListModel* model, - const GURL& url) override { + const GURL& url, + reading_list::EntrySource entry_source) override { observer_did_add_ += 1; } void ReadingListWillUpdateEntry(const ReadingListModel* model, @@ -334,7 +335,8 @@ ClearCounts(); const ReadingListEntry& entry = - model_->AddEntry(GURL("http://example.com"), "\n \tsample Test "); + model_->AddEntry(GURL("http://example.com"), "\n \tsample Test ", + reading_list::ADDED_VIA_CURRENT_APP); EXPECT_EQ(GURL("http://example.com"), entry.URL()); EXPECT_EQ("sample Test", entry.Title()); @@ -371,7 +373,8 @@ TEST_F(ReadingListModelTest, SyncMergeEntry) { auto storage = base::MakeUnique<TestReadingListStorage>(this); SetStorage(std::move(storage)); - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); model_->SetEntryDistilledPath(GURL("http://example.com"), base::FilePath("distilled/page.html")); const ReadingListEntry* local_entry = @@ -402,7 +405,8 @@ TEST_F(ReadingListModelTest, RemoveEntryByUrl) { auto storage = base::MakeUnique<TestReadingListStorage>(this); SetStorage(std::move(storage)); - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); EXPECT_NE(model_->GetEntryByURL(GURL("http://example.com")), nullptr); EXPECT_EQ(1ul, UnreadSize()); @@ -414,7 +418,8 @@ EXPECT_EQ(0ul, ReadSize()); EXPECT_EQ(model_->GetEntryByURL(GURL("http://example.com")), nullptr); - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); model_->SetReadStatus(GURL("http://example.com"), true); ClearCounts(); EXPECT_NE(model_->GetEntryByURL(GURL("http://example.com")), nullptr); @@ -431,7 +436,8 @@ TEST_F(ReadingListModelTest, RemoveSyncEntryByUrl) { auto storage = base::MakeUnique<TestReadingListStorage>(this); SetStorage(std::move(storage)); - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); EXPECT_NE(model_->GetEntryByURL(GURL("http://example.com")), nullptr); EXPECT_EQ(1ul, UnreadSize()); @@ -443,7 +449,8 @@ EXPECT_EQ(0ul, ReadSize()); EXPECT_EQ(model_->GetEntryByURL(GURL("http://example.com")), nullptr); - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); model_->SetReadStatus(GURL("http://example.com"), true); ClearCounts(); EXPECT_NE(model_->GetEntryByURL(GURL("http://example.com")), nullptr); @@ -458,7 +465,8 @@ } TEST_F(ReadingListModelTest, ReadEntry) { - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); model_->SetReadStatus(GURL("http://example.com"), true); @@ -479,7 +487,7 @@ GURL url1("http://example.com"); GURL url2("http://example2.com"); std::string entry1_title = "foo bar qux"; - model_->AddEntry(url1, entry1_title); + model_->AddEntry(url1, entry1_title, reading_list::ADDED_VIA_CURRENT_APP); // Check call with nullptr |read| parameter. const ReadingListEntry* entry1 = model_->GetEntryByURL(url1); @@ -502,7 +510,8 @@ TEST_F(ReadingListModelTest, UnreadEntry) { // Setup. - model_->AddEntry(GURL("http://example.com"), "sample"); + model_->AddEntry(GURL("http://example.com"), "sample", + reading_list::ADDED_VIA_CURRENT_APP); EXPECT_TRUE(model_->GetLocalUnseenFlag()); model_->SetReadStatus(GURL("http://example.com"), true); ClearCounts(); @@ -570,7 +579,8 @@ TEST_F(ReadingListModelTest, UpdateEntryTitle) { const GURL gurl("http://example.com"); - const ReadingListEntry& entry = model_->AddEntry(gurl, "sample"); + const ReadingListEntry& entry = + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); model_->SetEntryTitle(gurl, "ping"); @@ -580,7 +590,8 @@ TEST_F(ReadingListModelTest, UpdateEntryDistilledState) { const GURL gurl("http://example.com"); - const ReadingListEntry& entry = model_->AddEntry(gurl, "sample"); + const ReadingListEntry& entry = + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); model_->SetEntryDistilledState(gurl, ReadingListEntry::PROCESSING); @@ -590,7 +601,8 @@ TEST_F(ReadingListModelTest, UpdateDistilledPath) { const GURL gurl("http://example.com"); - const ReadingListEntry& entry = model_->AddEntry(gurl, "sample"); + const ReadingListEntry& entry = + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); ClearCounts(); model_->SetEntryDistilledPath(gurl, base::FilePath("distilled/page.html")); @@ -601,7 +613,7 @@ TEST_F(ReadingListModelTest, UpdateReadEntryTitle) { const GURL gurl("http://example.com"); - model_->AddEntry(gurl, "sample"); + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); model_->SetReadStatus(gurl, true); const ReadingListEntry* entry = model_->GetEntryByURL(gurl); ClearCounts(); @@ -613,7 +625,7 @@ TEST_F(ReadingListModelTest, UpdateReadEntryState) { const GURL gurl("http://example.com"); - model_->AddEntry(gurl, "sample"); + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); model_->SetReadStatus(gurl, true); const ReadingListEntry* entry = model_->GetEntryByURL(gurl); ClearCounts(); @@ -625,7 +637,7 @@ TEST_F(ReadingListModelTest, UpdateReadDistilledPath) { const GURL gurl("http://example.com"); - model_->AddEntry(gurl, "sample"); + model_->AddEntry(gurl, "sample", reading_list::ADDED_VIA_CURRENT_APP); model_->SetReadStatus(gurl, true); const ReadingListEntry* entry = model_->GetEntryByURL(gurl); ClearCounts();
diff --git a/components/reading_list/ios/reading_list_store_unittest.mm b/components/reading_list/ios/reading_list_store_unittest.mm index b13199e4..9ba369d4 100644 --- a/components/reading_list/ios/reading_list_store_unittest.mm +++ b/components/reading_list/ios/reading_list_store_unittest.mm
@@ -252,7 +252,8 @@ TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) { syncer::EntityDataMap remote_input; - model_->AddEntry(GURL("http://unread.example.com/"), "unread title"); + model_->AddEntry(GURL("http://unread.example.com/"), "unread title", + reading_list::ADDED_VIA_CURRENT_APP); base::test::ios::SpinRunLoopWithMinDelay( base::TimeDelta::FromMilliseconds(10)); @@ -285,7 +286,8 @@ base::test::ios::SpinRunLoopWithMinDelay( base::TimeDelta::FromMilliseconds(10)); syncer::EntityDataMap remote_input; - model_->AddEntry(GURL("http://unread.example.com/"), "new unread title"); + model_->AddEntry(GURL("http://unread.example.com/"), "new unread title", + reading_list::ADDED_VIA_CURRENT_APP); AssertCounts(0, 0, 0, 0, 0); std::unique_ptr<sync_pb::ReadingListSpecifics> specifics =
diff --git a/components/resources/OWNERS b/components/resources/OWNERS index 293f9d2..eb2ef926 100644 --- a/components/resources/OWNERS +++ b/components/resources/OWNERS
@@ -1,4 +1,5 @@ per-file autofill_scaled_resources.grdp=estade@chromium.org +per-file content_suggestions*=file://components/ntp_snippets/OWNERS per-file crash_*=cpu@chromium.org per-file crash_*=jochen@chromium.org per-file crash_*=mark@chromium.org @@ -17,7 +18,6 @@ per-file neterror*=juliatuttle@chromium.org per-file neterror*=mmenke@chromium.org per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS -per-file physical_web*=file://components/physical_web/OWNERS per-file proximity_auth*=tengs@chromium.org per-file supervised_user_error_page.grpd=aberent@chromium.org per-file supervised_user_error_page.grpd=bauerb@chromium.org
diff --git a/components/resources/components_scaled_resources.grd b/components/resources/components_scaled_resources.grd index 64b479d..511ec196 100644 --- a/components/resources/components_scaled_resources.grd +++ b/components/resources/components_scaled_resources.grd
@@ -13,10 +13,10 @@ <release seq="1"> <structures fallback_to_low_resolution="true"> <part file="autofill_scaled_resources.grdp" /> + <part file="content_suggestions_scaled_resources.grdp" /> <part file="crash_scaled_resources.grdp" /> <part file="flags_ui_scaled_resources.grdp" /> <part file="neterror_scaled_resources.grdp" /> - <part file="physical_web_scaled_resources.grdp" /> <part file="version_ui_scaled_resources.grdp" /> <!-- Generic resources -->
diff --git a/components/resources/physical_web_scaled_resources.grdp b/components/resources/content_suggestions_scaled_resources.grdp similarity index 60% rename from components/resources/physical_web_scaled_resources.grdp rename to components/resources/content_suggestions_scaled_resources.grdp index 38d23c4..12b382dc 100644 --- a/components/resources/physical_web_scaled_resources.grdp +++ b/components/resources/content_suggestions_scaled_resources.grdp
@@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <grit-part> - <structure type="chrome_scaled_image" name="IDR_PHYSICAL_WEB_LOGO" file="physical_web/logo.png" /> + <structure type="chrome_scaled_image" name="IDR_PHYSICAL_WEB_LOGO_WITH_PADDING" file="content_suggestions/physical_web_logo_with_padding.png" /> </grit-part>
diff --git a/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png new file mode 100644 index 0000000..271b580 --- /dev/null +++ b/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png Binary files differ
diff --git a/components/resources/default_100_percent/physical_web/logo.png b/components/resources/default_100_percent/physical_web/logo.png deleted file mode 100644 index 3007d0b..0000000 --- a/components/resources/default_100_percent/physical_web/logo.png +++ /dev/null Binary files differ
diff --git a/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png new file mode 100644 index 0000000..96aba76 --- /dev/null +++ b/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png Binary files differ
diff --git a/components/resources/default_200_percent/physical_web/logo.png b/components/resources/default_200_percent/physical_web/logo.png deleted file mode 100644 index 15ec0da..0000000 --- a/components/resources/default_200_percent/physical_web/logo.png +++ /dev/null Binary files differ
diff --git a/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png new file mode 100644 index 0000000..e1ebaed8 --- /dev/null +++ b/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png Binary files differ
diff --git a/components/resources/default_300_percent/physical_web/logo.png b/components/resources/default_300_percent/physical_web/logo.png deleted file mode 100644 index 821de18e..0000000 --- a/components/resources/default_300_percent/physical_web/logo.png +++ /dev/null Binary files differ
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 079bb3f..fcb2e27c 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -151,6 +151,7 @@ "//ui/shell_dialogs", "//ui/snapshot", "//ui/touch_selection", + "//v8:v8_version", ] public_deps = [
diff --git a/content/browser/devtools/DEPS b/content/browser/devtools/DEPS index 510478f3..0e86f42b 100644 --- a/content/browser/devtools/DEPS +++ b/content/browser/devtools/DEPS
@@ -3,5 +3,5 @@ "+grit/devtools_resources_map.h", # V8 version info - "+v8/include/v8.h", + "+v8/include/v8-version-string.h", ]
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc index bd980ec..58c0c46 100644 --- a/content/browser/devtools/devtools_http_handler.cc +++ b/content/browser/devtools/devtools_http_handler.cc
@@ -37,7 +37,7 @@ #include "net/server/http_server_request_info.h" #include "net/server/http_server_response_info.h" #include "net/socket/server_socket.h" -#include "v8/include/v8.h" +#include "v8/include/v8-version-string.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" @@ -525,7 +525,7 @@ version.SetString("WebKit-Version", GetWebKitVersion()); version.SetString("Browser", product_name_); version.SetString("User-Agent", user_agent_); - version.SetString("V8-Version", v8::V8::GetVersion()); + version.SetString("V8-Version", V8_VERSION_STRING); #if defined(OS_ANDROID) version.SetString("Android-Package", base::android::BuildInfo::GetInstance()->package_name());
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index fc8f8812..d900dfd 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1596,6 +1596,9 @@ } void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) { + if (!is_active()) + return; + // Validate the URLs in |params|. If the renderer can't request the URLs // directly, don't show them in the context menu. ContextMenuParams validated_params(params);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 7da685df..eb809c41 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -648,6 +648,8 @@ RenderViewHostStaysActiveWithLateSwapoutACK); FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, LoadEventForwardingWhilePendingDeletion); + FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, + ContextMenuAfterCrossProcessNavigation); // IPC Message handlers. void OnDidAddMessageToConsole(int32_t level,
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h index 3109d04..7c7e10c6 100644 --- a/content/browser/renderer_host/input/input_router_impl.h +++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -201,10 +201,6 @@ int routing_id() const { return routing_id_; } - TouchAction allowed_touch_action() { - return touch_action_filter_.allowed_touch_action(); - } - IPC::Sender* sender_; InputRouterClient* client_; InputAckHandler* ack_handler_;
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc index d0c9b32..9bb4969e 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -156,11 +156,6 @@ base::RetainedRef(controller), error_code)); } -void AudioInputRendererHost::OnData(media::AudioInputController* controller, - const media::AudioBus* data) { - NOTREACHED() << "Only low-latency mode is supported."; -} - void AudioInputRendererHost::OnLog(media::AudioInputController* controller, const std::string& message) { BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, @@ -180,7 +175,6 @@ AudioEntry* entry = LookupByController(controller); DCHECK(entry); DCHECK(PeerHandle()); - DCHECK(entry->controller->SharedMemoryAndSyncSocketMode()); // Once the audio stream is created then complete the creation process by // mapping shared memory and sharing with the renderer process.
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h index e4bf199cc..fdd979ab 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.h +++ b/content/browser/renderer_host/media/audio_input_renderer_host.h
@@ -108,8 +108,6 @@ void OnCreated(media::AudioInputController* controller) override; void OnError(media::AudioInputController* controller, media::AudioInputController::ErrorCode error_code) override; - void OnData(media::AudioInputController* controller, - const media::AudioBus* data) override; void OnLog(media::AudioInputController* controller, const std::string& message) override; @@ -238,7 +236,7 @@ AudioEntryMap audio_entries_; // Raw pointer of the UserInputMonitor. - media::UserInputMonitor* user_input_monitor_; + media::UserInputMonitor* const user_input_monitor_; std::unique_ptr<media::AudioLog> audio_log_;
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc index 3a62616..375da42c 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host_unittest.cc
@@ -162,13 +162,13 @@ media::AudioManager* audio_manager, AudioInputController::EventHandler* event_handler, media::UserInputMonitor* user_input_monitor) - : AudioInputController(event_handler, + : AudioInputController(std::move(task_runner), + event_handler, writer, /*debug_writer*/ nullptr, user_input_monitor, /*agc*/ false) { - task_runner_ = std::move(task_runner); - task_runner_->PostTask( + GetTaskRunnerForTesting()->PostTask( FROM_HERE, base::Bind(&AudioInputController::EventHandler::OnCreated, base::Unretained(event_handler), base::Unretained(this))); @@ -178,7 +178,7 @@ .WillByDefault(SaveArg<0>(&file_name)); } - EventHandler* handler() { return handler_; } + EventHandler* handler() { return GetHandlerForTesting(); } // File name that we pretend to do a debug recording to, if any. base::FilePath debug_file_name() { return file_name; } @@ -202,7 +202,8 @@ void ExecuteClose(const base::Closure& task) { // Hop to audio manager thread before calling task, since this is the real // behavior. - task_runner_->PostTaskAndReply(FROM_HERE, base::Bind([]() {}), task); + GetTaskRunnerForTesting()->PostTaskAndReply(FROM_HERE, base::Bind([]() {}), + task); } base::FilePath file_name;
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index 122e9311..6c712a3 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -196,12 +196,8 @@ NOTREACHED() << "Should only receive one reply per event"; // |fetch_dispatcher| is null if the URLRequest was killed. - if (fetch_dispatcher_) { - // TODO(falken): Remove this CHECK once https://crbug.com/485900 is - // resolved. - CHECK(version_->GetMainScriptHttpResponseInfo()); + if (fetch_dispatcher_) fetch_dispatcher_->DidFinish(request_id, fetch_result, response); - } } private: @@ -300,9 +296,6 @@ DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status()) << "Worker stopped too soon after it was started."; - // TODO(falken): Remove this CHECK once https://crbug.com/485900 is resolved. - CHECK(version_->GetMainScriptHttpResponseInfo()); - DCHECK(!prepare_callback_.is_null()); base::Closure prepare_callback = prepare_callback_; prepare_callback.Run();
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.cc b/content/browser/service_worker/service_worker_read_from_cache_job.cc index fea3d199..c0d4966 100644 --- a/content/browser/service_worker/service_worker_read_from_cache_job.cc +++ b/content/browser/service_worker/service_worker_read_from_cache_job.cc
@@ -35,7 +35,12 @@ resource_id_(resource_id), context_(context), version_(version), - weak_factory_(this) {} + weak_factory_(this) { + DCHECK(version_); + DCHECK(resource_type_ == RESOURCE_TYPE_SCRIPT || + (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER && + version_->script_url() == request_->url())); +} ServiceWorkerReadFromCacheJob::~ServiceWorkerReadFromCacheJob() { } @@ -165,11 +170,8 @@ if (is_range_request()) SetupRangeResponse(http_info_io_buffer_->response_data_size); http_info_io_buffer_ = nullptr; - if (is_main_script()) { - // TODO(nhiroki): Temporary check for debugging (https://crbug.com/485900). - CHECK_EQ(request_->url(), version_->script_url()); + if (is_main_script()) version_->SetMainScriptHttpResponseInfo(*http_info_); - } TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerReadFromCacheJob::ReadInfo", this,
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc b/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc index b0fb55e..81c64a9 100644 --- a/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc +++ b/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
@@ -35,6 +35,7 @@ const int64_t kVersionId = 2; const int64_t kMainScriptResourceId = 10; const int64_t kImportedScriptResourceId = 11; +const int64_t kNonExistentResourceId = 12; const int64_t kResourceSize = 100; void DidStoreRegistration(ServiceWorkerStatusCode* status_out, @@ -227,11 +228,20 @@ TEST_F(ServiceWorkerReadFromCacheJobTest, ResourceNotFound) { ASSERT_EQ(SERVICE_WORKER_OK, FindRegistration()); - // Try to read a nonexistent resource from the diskcache. + // Populate the script cache map with a nonexistent resource. + ServiceWorkerScriptCacheMap* script_cache_map = version_->script_cache_map(); + script_cache_map->resource_map_.clear(); + using Record = ServiceWorkerDatabase::ResourceRecord; + std::vector<Record> resources = { + Record(kNonExistentResourceId, main_script_.url, main_script_.size_bytes), + Record(imported_script_.resource_id, imported_script_.url, + imported_script_.size_bytes)}; + script_cache_map->SetResources(resources); + + // Attempt to read it from the disk cache. std::unique_ptr<net::URLRequest> request = - url_request_context_->CreateRequest( - GURL("http://example.com/nonexistent"), net::DEFAULT_PRIORITY, - &delegate_); + url_request_context_->CreateRequest(main_script_.url, + net::DEFAULT_PRIORITY, &delegate_); const int64_t kNonexistentResourceId = 100; test_job_interceptor_->set_main_intercept_job( base::MakeUnique<ServiceWorkerReadFromCacheJob>(
diff --git a/content/browser/service_worker/service_worker_script_cache_map.h b/content/browser/service_worker/service_worker_script_cache_map.h index ac4436d..0051d68 100644 --- a/content/browser/service_worker/service_worker_script_cache_map.h +++ b/content/browser/service_worker/service_worker_script_cache_map.h
@@ -75,6 +75,7 @@ friend class ServiceWorkerVersion; FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest, ReadResourceFailure_WaitingWorker); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerReadFromCacheJobTest, ResourceNotFound); ServiceWorkerScriptCacheMap( ServiceWorkerVersion* owner,
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc index da9a6f9..77a82de8 100644 --- a/content/browser/service_worker/service_worker_url_request_job.cc +++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -599,8 +599,7 @@ } // We should have a response now. - // TODO(falken): Turn to DCHECK once https://crbug.com/485900 is resolved. - CHECK_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, fetch_result); + DCHECK_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, fetch_result); // A response with status code 0 is Blink telling us to respond with network // error. @@ -621,15 +620,8 @@ DCHECK(version); const net::HttpResponseInfo* main_script_http_info = version->GetMainScriptHttpResponseInfo(); - CHECK(main_script_http_info); - if (main_script_http_info) { - // In normal case |main_script_http_info| must be set while starting the - // ServiceWorker. But when the ServiceWorker registration database was not - // written correctly, it may be null. - // TODO(horo): Change this line to DCHECK when crbug.com/485900 is fixed. - http_response_info_.reset( - new net::HttpResponseInfo(*main_script_http_info)); - } + DCHECK(main_script_http_info); + http_response_info_.reset(new net::HttpResponseInfo(*main_script_http_info)); // Set up a request for reading the stream. if (response.stream_url.is_valid()) {
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index dbbcd8a..34437e85 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -661,9 +661,6 @@ const StatusCallback& error_callback) { if (running_status() == EmbeddedWorkerStatus::RUNNING) { DCHECK(start_callbacks_.empty()); - // TODO(falken): Remove this CHECK once https://crbug.com/485900 is - // resolved. - CHECK(GetMainScriptHttpResponseInfo()); task.Run(); return; } @@ -1520,9 +1517,6 @@ switch (running_status()) { case EmbeddedWorkerStatus::RUNNING: - // TODO(falken): Remove this CHECK once https://crbug.com/485900 is - // resolved. - CHECK(GetMainScriptHttpResponseInfo()); RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); return; case EmbeddedWorkerStatus::STARTING: @@ -1953,11 +1947,6 @@ void ServiceWorkerVersion::FinishStartWorker(ServiceWorkerStatusCode status) { start_worker_first_purpose_ = base::nullopt; - if (status == SERVICE_WORKER_OK) { - // TODO(falken): Remove this CHECK once https://crbug.com/485900 is - // resolved. - CHECK(GetMainScriptHttpResponseInfo()); - } RunCallbacks(this, &start_callbacks_, status); }
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc index 1deab98e..6ed0a5ce 100644 --- a/content/browser/service_worker/service_worker_write_to_cache_job.cc +++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -81,6 +81,10 @@ did_notify_started_(false), did_notify_finished_(false), weak_factory_(this) { + DCHECK(version_); + DCHECK(resource_type_ == RESOURCE_TYPE_SCRIPT || + (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER && + version_->script_url() == url_)); InitNetRequest(extra_load_flags); } @@ -299,9 +303,6 @@ } if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER) { - // TODO(nhiroki): Temporary check for debugging (https://crbug.com/485900). - CHECK_EQ(version_->script_url(), url_); - std::string mime_type; request->GetMimeType(&mime_type); if (mime_type != "application/x-javascript" &&
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 5802527..6d46c96 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -5384,6 +5384,7 @@ // aren't at present, and if they become the same this test will need to be // updated to accommodate. EXPECT_NE(TOUCH_ACTION_AUTO, TOUCH_ACTION_NONE); + // Verify the child's input router is initially set for TOUCH_ACTION_AUTO. The // TouchStart event will trigger TOUCH_ACTION_NONE being sent back to the // browser. @@ -5391,7 +5392,8 @@ root->child_at(0)->current_frame_host()->GetRenderWidgetHost(); InputRouterImpl* child_input_router = static_cast<InputRouterImpl*>(child_render_widget_host->input_router()); - EXPECT_EQ(TOUCH_ACTION_AUTO, child_input_router->allowed_touch_action()); + EXPECT_EQ(TOUCH_ACTION_AUTO, + child_input_router->touch_action_filter_.allowed_touch_action()); // Simulate touch event to sub-frame. gfx::Point child_center(150, 150); @@ -5410,7 +5412,8 @@ // Verify the presence of the touch handler in the child frame correctly // propagates touch-action:none information back to the child's input router. - EXPECT_EQ(TOUCH_ACTION_NONE, child_input_router->allowed_touch_action()); + EXPECT_EQ(TOUCH_ACTION_NONE, + child_input_router->touch_action_filter_.allowed_touch_action()); } namespace { @@ -9065,4 +9068,34 @@ EXPECT_EQ("This page has no title.", result); } +// Tests that trying to open a context menu in the old RFH after commiting a +// navigation doesn't crash the browser. https://crbug.com/677266. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + ContextMenuAfterCrossProcessNavigation) { + // Navigate to a.com. + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); + + // Disable the swapout ACK and the swapout timer. + RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>( + shell()->web_contents()->GetMainFrame()); + scoped_refptr<SwapoutACKMessageFilter> filter = new SwapoutACKMessageFilter(); + rfh->GetProcess()->AddFilter(filter.get()); + rfh->DisableSwapOutTimerForTesting(); + + // Open a popup on a.com to keep the process alive. + OpenPopup(shell(), embedded_test_server()->GetURL("a.com", "/title2.html"), + "foo"); + + // Cross-process navigation to b.com. + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.com", "/title3.html"))); + + // Pretend that a.com just requested a context menu. This used to cause a + // because the RenderWidgetHostView is destroyed when the frame is swapped and + // added to pending delete list. + rfh->OnMessageReceived( + FrameHostMsg_ContextMenu(rfh->GetRoutingID(), ContextMenuParams())); +} + } // namespace content
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc index ac6bcbc..7ddd4ee0 100644 --- a/content/browser/speech/speech_recognition_browsertest.cc +++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -156,7 +156,7 @@ audio_bus->FromInterleaved(&audio_buffer.get()[0], audio_bus->frames(), audio_params.bits_per_sample() / 8); - controller->event_handler()->OnData(controller.get(), audio_bus.get()); + controller->sync_writer()->Write(audio_bus.get(), 0.0, false, 0); } void FeedAudioController(int duration_ms, bool feed_with_noise) {
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc index 0bc62614..d79c171 100644 --- a/content/browser/speech/speech_recognizer_impl.cc +++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -276,8 +276,10 @@ this, event_args)); } -void SpeechRecognizerImpl::OnData(AudioInputController* controller, - const AudioBus* data) { +void SpeechRecognizerImpl::Write(const AudioBus* data, + double volume, + bool key_pressed, + uint32_t hardware_delay_bytes) { // Convert audio from native format to fixed format used by WebSpeech. FSMEventArgs event_args(EVENT_AUDIO_DATA); event_args.audio_data = audio_converter_->Convert(data); @@ -297,6 +299,8 @@ CHECK(audio_converter_->data_was_converted()); } +void SpeechRecognizerImpl::Close() {} + void SpeechRecognizerImpl::OnAudioClosed(AudioInputController*) {} void SpeechRecognizerImpl::OnSpeechRecognitionEngineResults( @@ -585,7 +589,7 @@ new OnDataConverter(input_parameters, output_parameters)); audio_controller_ = AudioInputController::Create( - audio_manager, this, input_parameters, device_id_, NULL); + audio_manager, this, this, input_parameters, device_id_, NULL); if (!audio_controller_.get()) { return Abort(
diff --git a/content/browser/speech/speech_recognizer_impl.h b/content/browser/speech/speech_recognizer_impl.h index e0a632e9..f284171 100644 --- a/content/browser/speech/speech_recognizer_impl.h +++ b/content/browser/speech/speech_recognizer_impl.h
@@ -32,6 +32,7 @@ class CONTENT_EXPORT SpeechRecognizerImpl : public SpeechRecognizer, public media::AudioInputController::EventHandler, + public media::AudioInputController::SyncWriter, public NON_EXPORTED_BASE(SpeechRecognitionEngine::Delegate) { public: static const int kAudioSampleRate; @@ -134,11 +135,16 @@ void OnCreated(media::AudioInputController* controller) override {} void OnError(media::AudioInputController* controller, media::AudioInputController::ErrorCode error_code) override; - void OnData(media::AudioInputController* controller, - const media::AudioBus* data) override; void OnLog(media::AudioInputController* controller, const std::string& message) override {} + // AudioInputController::SyncWriter methods. + void Write(const media::AudioBus* data, + double volume, + bool key_pressed, + uint32_t hardware_delay_bytes) override; + void Close() override; + // SpeechRecognitionEngineDelegate methods. void OnSpeechRecognitionEngineResults( const SpeechRecognitionResults& results) override;
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc index 62eae102..80b94bc 100644 --- a/content/browser/speech/speech_recognizer_impl_unittest.cc +++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -183,6 +183,12 @@ CopyPacketToAudioBus(); } + void OnData(media::AudioBus* data) { + auto* writer = + static_cast<AudioInputController::SyncWriter*>(recognizer_.get()); + writer->Write(data, 0.0, false, 0); + } + protected: TestBrowserThreadBundle thread_bundle_; scoped_refptr<SpeechRecognizerImpl> recognizer_; @@ -247,7 +253,7 @@ // full recording to complete. const size_t kNumChunks = 5; for (size_t i = 0; i < kNumChunks; ++i) { - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); ASSERT_TRUE(fetcher); @@ -302,7 +308,7 @@ TestAudioInputController* controller = audio_input_controller_factory_.controller(); ASSERT_TRUE(controller); - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); recognizer_->AbortRecognition(); base::RunLoop().RunUntilIdle(); @@ -323,7 +329,7 @@ TestAudioInputController* controller = audio_input_controller_factory_.controller(); ASSERT_TRUE(controller); - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); ASSERT_TRUE(fetcher); @@ -359,7 +365,7 @@ TestAudioInputController* controller = audio_input_controller_factory_.controller(); ASSERT_TRUE(controller); - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); ASSERT_TRUE(fetcher); @@ -412,7 +418,7 @@ TestAudioInputController* controller = audio_input_controller_factory_.controller(); ASSERT_TRUE(controller); - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); controller->event_handler()->OnError(controller, AudioInputController::UNKNOWN_ERROR); base::RunLoop().RunUntilIdle(); @@ -438,7 +444,7 @@ SpeechRecognitionEngine::kAudioPacketIntervalMs + 1; // The vector is already filled with zero value samples on create. for (int i = 0; i < num_packets; ++i) { - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); } base::RunLoop().RunUntilIdle(); EXPECT_TRUE(recognition_started_); @@ -467,12 +473,12 @@ // The vector is already filled with zero value samples on create. for (int i = 0; i < num_packets / 2; ++i) { - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); } FillPacketWithTestWaveform(); for (int i = 0; i < num_packets / 2; ++i) { - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); } base::RunLoop().RunUntilIdle(); @@ -504,18 +510,18 @@ SpeechRecognitionEngine::kAudioPacketIntervalMs; FillPacketWithNoise(); for (int i = 0; i < num_packets; ++i) { - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); } base::RunLoop().RunUntilIdle(); EXPECT_EQ(-1.0f, volume_); // No audio volume set yet. // The vector is already filled with zero value samples on create. - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); EXPECT_FLOAT_EQ(0.74939233f, volume_); FillPacketWithTestWaveform(); - controller->event_handler()->OnData(controller, audio_bus_.get()); + OnData(audio_bus_.get()); base::RunLoop().RunUntilIdle(); EXPECT_NEAR(0.89926866f, volume_, 0.00001f); EXPECT_FLOAT_EQ(0.75071919f, noise_volume_);
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 68f011f..3686e85 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -30,7 +30,7 @@ #include "content/public/common/content_switches.h" #include "gpu/config/gpu_info.h" #include "net/base/network_change_notifier.h" -#include "v8/include/v8.h" +#include "v8/include/v8-version-string.h" #if (defined(OS_POSIX) && defined(USE_UDEV)) || defined(OS_WIN) || \ defined(OS_MACOSX) @@ -115,7 +115,7 @@ metadata_dict->SetString("network-type", GetNetworkTypeString()); metadata_dict->SetString("product-version", GetContentClient()->GetProduct()); - metadata_dict->SetString("v8-version", v8::V8::GetVersion()); + metadata_dict->SetString("v8-version", V8_VERSION_STRING); metadata_dict->SetString("user-agent", GetContentClient()->GetUserAgent()); // OS
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc index 36bb9a6..b7a055c 100644 --- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc +++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -23,6 +23,7 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" +#include "media/audio/audio_manager.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/perf/perf_test.h" @@ -579,6 +580,31 @@ ExecuteJavascriptAndReturnResult(call)); } +#if defined(OS_ANDROID) +// Disabled until http://crbug.com/679302 is fixed. +#define MAYBE_GetUserMediaFailToAccessAudioDevice \ + DISABLED_GetUserMediaFailToAccessAudioDevice +#else +#define MAYBE_GetUserMediaFailToAccessAudioDevice \ + GetUserMediaFailToAccessAudioDevice +#endif +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, + MAYBE_GetUserMediaFailToAccessAudioDevice) { + ASSERT_TRUE(embedded_test_server()->Start()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + // Set the maximum allowed input and output streams to 0 + // so that the call to create a new audio input stream will fail. + media::AudioManager::Get()->SetMaxStreamCountForTesting(0, 0); + + const std::string call = base::StringPrintf( + "%s({video: false, audio: true});", kGetUserMediaAndExpectFailure); + EXPECT_EQ("TrackStartError", + ExecuteJavascriptAndReturnResult(call)); +} + // This test makes two getUserMedia requests, one with impossible constraints // that should trigger an error, and one with valid constraints. The test // verifies getUserMedia can succeed after being given impossible constraints.
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc index 3be984a..8c94e7a5 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -145,14 +145,15 @@ // rid of the entire check, and run SubscribeToNotifications on all // platforms. // +// TODO(http://crbug.com/633191): Remove OS_MACOSX from this check. // TODO(http://crbug.com/636270): Remove OS_WIN from this check. -#if defined(OS_WIN) +#if defined(OS_MACOSX) || defined(OS_WIN) base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic::OnStartNotifySessionError, GetWeakPtr(), error_callback, BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED)); -#else // defined(OS_WIN)) +#else // !(defined(OS_MACOSX) || defined(OS_WIN)) // Find the Client Characteristic Configuration descriptor. std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor = GetDescriptorsByUUID(BluetoothRemoteGattDescriptor:: @@ -182,7 +183,7 @@ GetWeakPtr(), callback), base::Bind(&BluetoothRemoteGattCharacteristic::OnStartNotifySessionError, GetWeakPtr(), error_callback)); -#endif // defined(OS_WIN) +#endif // defined(OS_MACOSX) || defined(OS_WIN) } void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h index 4132f8e..c690aea 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
@@ -48,6 +48,10 @@ std::vector<BluetoothRemoteGattDescriptor*> GetDescriptors() const override; BluetoothRemoteGattDescriptor* GetDescriptor( const std::string& identifier) const override; + void StartNotifySession(const NotifySessionCallback& callback, + const ErrorCallback& error_callback) override; + void StopNotifySession(BluetoothGattNotifySession* session, + const base::Closure& callback) override; void ReadRemoteCharacteristic(const ValueCallback& callback, const ErrorCallback& error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, @@ -122,8 +126,9 @@ std::pair<ValueCallback, ErrorCallback> read_characteristic_value_callbacks_; // WriteRemoteCharacteristic request callbacks. std::pair<base::Closure, ErrorCallback> write_characteristic_value_callbacks_; - // Stores SubscribeToNotifications request callbacks. - typedef std::pair<base::Closure, const ErrorCallback> PendingStartNotifyCall; + // Stores StartNotifySession request callbacks. + typedef std::pair<NotifySessionCallback, ErrorCallback> + PendingStartNotifyCall; std::vector<PendingStartNotifyCall> start_notify_session_callbacks_; // Flag indicates if GATT event registration is in progress. bool start_notifications_in_progress_;
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm index c5b2b14a..c04df6a 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -150,6 +150,50 @@ searched_pair->second.get()); } +void BluetoothRemoteGattCharacteristicMac::StartNotifySession( + const NotifySessionCallback& callback, + const ErrorCallback& error_callback) { + if (IsNotifying()) { + VLOG(2) << "Already notifying. Creating notify session."; + std::unique_ptr<BluetoothGattNotifySession> notify_session( + new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(callback, base::Passed(std::move(notify_session)))); + return; + } + + if (!SupportsNotificationsOrIndications()) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(error_callback, + BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED)); + return; + } + + start_notify_session_callbacks_.push_back( + std::make_pair(callback, error_callback)); + + if (start_notifications_in_progress_) { + VLOG(2) << "Start Notifications already in progress. " + << "Request has been queued."; + return; + } + + [GetCBPeripheral() setNotifyValue:YES + forCharacteristic:cb_characteristic_.get()]; + start_notifications_in_progress_ = true; +} + +void BluetoothRemoteGattCharacteristicMac::StopNotifySession( + BluetoothGattNotifySession* session, + const base::Closure& callback) { + // TODO(http://crbug.com/633191): Remove this method and use the base version. + // Instead, we should implement SubscribeToNotifications and + // UnsubscribeFromNotifications. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback); +} + void BluetoothRemoteGattCharacteristicMac::ReadRemoteCharacteristic( const ValueCallback& callback, const ErrorCallback& error_callback) { @@ -212,34 +256,8 @@ BluetoothRemoteGattDescriptor* ccc_descriptor, const base::Closure& callback, const ErrorCallback& error_callback) { - if (IsNotifying()) { - VLOG(2) << "Already notifying. Creating notify session."; - std::unique_ptr<BluetoothGattNotifySession> notify_session( - new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr())); - callback.Run(); - return; - } - - if (!SupportsNotificationsOrIndications()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(error_callback, - BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED)); - return; - } - - start_notify_session_callbacks_.push_back( - std::make_pair(callback, error_callback)); - - if (start_notifications_in_progress_) { - VLOG(2) << "Start Notifications already in progress. " - << "Request has been queued."; - return; - } - - [GetCBPeripheral() setNotifyValue:YES - forCharacteristic:cb_characteristic_.get()]; - start_notifications_in_progress_ = true; + // TODO(http://crbug.com/633191): Implement this method + NOTIMPLEMENTED(); } void BluetoothRemoteGattCharacteristicMac::UnsubscribeFromNotifications( @@ -318,7 +336,8 @@ void BluetoothRemoteGattCharacteristicMac::DidUpdateNotificationState( NSError* error) { - std::vector<PendingStartNotifyCall> reentrant_safe_callbacks; + std::vector<std::pair<NotifySessionCallback, ErrorCallback>> + reentrant_safe_callbacks; reentrant_safe_callbacks.swap(start_notify_session_callbacks_); start_notifications_in_progress_ = false; if (error) { @@ -335,7 +354,8 @@ return; } for (const auto& callback : reentrant_safe_callbacks) { - callback.first.Run(); + callback.first.Run(base::MakeUnique<BluetoothGattNotifySession>( + weak_ptr_factory_.GetWeakPtr())); } }
diff --git a/docs/layout_tests_linux.md b/docs/layout_tests_linux.md index b1c57e4..1dfd168 100644 --- a/docs/layout_tests_linux.md +++ b/docs/layout_tests_linux.md
@@ -40,27 +40,6 @@ sudo apt-get remove totem-mozilla - -## Running layout tests under valgrind on Linux - -As above, but use `tools/valgrind/chrome_tests.sh -t webkit` instead. e.g. - - sh tools/valgrind/chrome_tests.sh -t webkit LayoutTests/fast/ - -This defaults to using --debug. Read the script for more details. - -If you're trying to reproduce a run from the valgrind buildbot, look for the -`--run_chunk=XX:YY` line in the bot's log. You can rerun exactly as the bot did -with the commands. - -```shell -cd ~/chromium/src -echo XX > valgrind_layout_chunk.txt -sh tools/valgrind/chrome_tests.sh -t layout -n YY -``` - -That will run the XXth chunk of YY layout tests. - ## Configuration tips * Use an optimized `content_shell` when rebaselining or running a lot of
diff --git a/docs/linux_debugging.md b/docs/linux_debugging.md index 3f53fc3..c26a2271 100644 --- a/docs/linux_debugging.md +++ b/docs/linux_debugging.md
@@ -411,29 +411,6 @@ up to date. In case this file reference goes out of date, try looking for usage of macros like `IPC_MESSAGE_LOG_ENABLED` or `IPC_MESSAGE_MACROS_LOG_ENABLED`. -## Using valgrind - -To run valgrind on the browser and renderer processes, with our suppression file -and flags: - - $ cd $CHROMIUM_ROOT/src - $ tools/valgrind/valgrind.sh out/Debug/chrome - -You can use valgrind on chrome and/or on the renderers e.g -`valgrind --smc-check=all ../sconsbuild/Debug/chrome` -or by passing valgrind as the argument to `--render-cmd-prefix`. - -Beware that there are several valgrind "false positives" e.g. pickle, sqlite and -some instances in webkit that are ignorable. On systems with prelink and address -space randomization (e.g. Fedora), you may also see valgrind errors in libstdc++ -on startup and in gnome-breakpad. - -Valgrind doesn't seem to play nice with tcmalloc. To disable tcmalloc set the GN arg: - - use_allocator="none" - -and rebuild. - ## Profiling See
diff --git a/docs/linux_profiling.md b/docs/linux_profiling.md index 4d9ce0f..694e4e9 100644 --- a/docs/linux_profiling.md +++ b/docs/linux_profiling.md
@@ -161,37 +161,6 @@ For further information, please refer to http://google-perftools.googlecode.com/svn/trunk/doc/heapprofile.html. -### Massif - -[Massif](http://valgrind.org/docs/manual/mc-manual.html) is a -[Valgrind](https://www.chromium.org/developers/how-tos/using-valgrind)-based heap -profiler. It is much slower than the heap profiler from google-perftools, but it -may have some advantages. (In particular, it handles the multi-process -executables well). - -First, you will need to build massif from valgrind-variant project yourself, -it's [easy](http://code.google.com/p/valgrind-variant/wiki/HowTo). - -Then, make sure your Chromium is built using the -[valgrind instructions](https://www.chromium.org/developers/how-tos/using-valgrind). -Now, you can run massif like this: - -``` -path-to-valgrind-variant/valgrind/inst/bin/valgrind \ - --fullpath-after=/chromium/src/ \ - --trace-children-skip=*npviewer*,/bin/uname,/bin/sh,/usr/bin/which,/bin/ps,/bin/grep,/usr/bin/linux32 \ - --trace-children=yes \ - --tool=massif \ - out/Release/chrome --noerrdialogs --disable-hang-monitor --other-chrome-flags -``` - -The result will be stored in massif.out.PID files, which you can post-process -with [ms_print](http://valgrind.org/docs/manual/mc-manual.html). - -TODO(kcc) sometimes when closing a tab the main process kills the tab process -before massif completes writing it's log file. Need a flag that tells the main -process to wait longer. - ## Paint profiling You can use Xephyr to profile how chrome repaints the screen. Xephyr is a
diff --git a/google_apis/gcm/engine/connection_event_tracker.cc b/google_apis/gcm/engine/connection_event_tracker.cc index 50a5ecdcc..f2be7c8 100644 --- a/google_apis/gcm/engine/connection_event_tracker.cc +++ b/google_apis/gcm/engine/connection_event_tracker.cc
@@ -25,6 +25,10 @@ completed_events_.size(), kMaxClientEvents + 1); } +bool ConnectionEventTracker::IsEventInProgress() const { + return current_event_.has_time_connection_started_ms(); +} + void ConnectionEventTracker::StartConnectionAttempt() { // TODO(harkness): Can we dcheck here that there is not an in progress // connection? @@ -36,14 +40,15 @@ } void ConnectionEventTracker::EndConnectionAttempt() { - // TODO(harkness): Modify tests so that we can put a DCHECK here. + DCHECK(IsEventInProgress()); + if (completed_events_.size() == kMaxClientEvents) { // Don't let the completed events grow beyond the max. completed_events_.pop_front(); number_discarded_events_++; } - // Current event is now completed, so add it to our list of completed events. + // Current event is finished, so add it to our list of completed events. current_event_.set_time_connection_ended_ms(base::Time::Now().ToJavaTime()); completed_events_.push_back(current_event_); current_event_.Clear();
diff --git a/google_apis/gcm/engine/connection_event_tracker.h b/google_apis/gcm/engine/connection_event_tracker.h index 2e18273..6c3a54d 100644 --- a/google_apis/gcm/engine/connection_event_tracker.h +++ b/google_apis/gcm/engine/connection_event_tracker.h
@@ -22,6 +22,9 @@ ConnectionEventTracker(); ~ConnectionEventTracker(); + // Returns a boolean indicating whether an attempt is currently in progress. + bool IsEventInProgress() const; + // Start recording a new connection attempt. This should never be called if // a connection attempt is already ongoing. void StartConnectionAttempt();
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc index 2d459f2..1eba5809 100644 --- a/google_apis/gcm/engine/connection_factory_impl.cc +++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -209,9 +209,14 @@ // connection. } - if (reason == LOGIN_FAILURE) - event_tracker_.ConnectionLoginFailed(); - event_tracker_.EndConnectionAttempt(); + // SignalConnectionReset can be called at any time without regard to whether + // a connection attempt is currently in progress. Only notify the event + // tracker if there is an event in progress. + if (event_tracker_.IsEventInProgress()) { + if (reason == LOGIN_FAILURE) + event_tracker_.ConnectionLoginFailed(); + event_tracker_.EndConnectionAttempt(); + } CloseSocket(); DCHECK(!IsEndpointReachable());
diff --git a/google_apis/gcm/engine/connection_factory_impl_unittest.cc b/google_apis/gcm/engine/connection_factory_impl_unittest.cc index 3d0f52b3..ed91e4b 100644 --- a/google_apis/gcm/engine/connection_factory_impl_unittest.cc +++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
@@ -602,7 +602,7 @@ // There should be one failed client event for each failed connection, but // there is a maximum cap of kMaxClientEvents, which is 30. There should also // be a single event which records the events which were discarded. - const auto client_events = GetClientEvents(); + auto client_events = GetClientEvents(); ASSERT_EQ(31, client_events.size()); bool found_discarded_events = false; @@ -626,8 +626,21 @@ EXPECT_TRUE(connected_server().is_valid()); // Old client events should have been reset after the successful connection. - const auto new_client_events = GetClientEvents(); - ASSERT_EQ(0, new_client_events.size()); + client_events = GetClientEvents(); + ASSERT_EQ(0, client_events.size()); + + // Test that EndConnectionAttempt doesn't write empty events to the tracker. + // There should be 2 events: 1) the successful connection which was previously + // established. 2) the unsuccessful connection triggered as a result of the + // SOCKET_FAILURE signal. The NETWORK_CHANGE signal should not cause an + // additional event since there is no in progress event. + factory()->SetConnectResult(net::ERR_CONNECTION_FAILED); + factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE); + factory()->SignalConnectionReset(ConnectionFactory::NETWORK_CHANGE); + WaitForConnections(); + + client_events = GetClientEvents(); + ASSERT_EQ(2, client_events.size()); } } // namespace gcm
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn index fdb46c5..adfa6b7 100644 --- a/ios/chrome/browser/browser_state/BUILD.gn +++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -8,11 +8,13 @@ "browser_state_otr_helper.h", "chrome_browser_state.h", "chrome_browser_state.mm", + "chrome_browser_state_manager.h", ] deps = [ "//base", "//components/prefs", "//components/sync_preferences", + "//ios/chrome/browser/tabs", "//ios/web", "//net", ] @@ -35,7 +37,6 @@ "chrome_browser_state_impl_io_data.mm", "chrome_browser_state_io_data.cc", "chrome_browser_state_io_data.h", - "chrome_browser_state_manager.h", "chrome_browser_state_manager_impl.cc", "chrome_browser_state_manager_impl.h", "chrome_browser_state_removal_controller.h",
diff --git a/ios/chrome/browser/browser_state_metrics/BUILD.gn b/ios/chrome/browser/browser_state_metrics/BUILD.gn index 1993bb75..5c6756b 100644 --- a/ios/chrome/browser/browser_state_metrics/BUILD.gn +++ b/ios/chrome/browser/browser_state_metrics/BUILD.gn
@@ -9,5 +9,6 @@ ] deps = [ "//components/profile_metrics", + "//ios/chrome/browser/browser_state", ] }
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn index cfccc2c..cc28d43 100644 --- a/ios/chrome/browser/metrics/BUILD.gn +++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -48,7 +48,7 @@ "//ios/chrome/browser/google", "//ios/chrome/browser/signin", "//ios/chrome/browser/sync", - "//ios/chrome/browser/ui:browser_list", + "//ios/chrome/browser/tabs", "//ios/chrome/browser/variations", "//ios/chrome/browser/variations:ios_chrome_ui_string_overrider_factory", "//ios/chrome/common", @@ -101,7 +101,6 @@ "//ios/chrome/browser/browser_state", "//ios/chrome/browser/tabs", "//ios/chrome/browser/ui", - "//ios/chrome/browser/ui:browser_list", "//ios/web", "//ui/base", "//url",
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm index 3fbd9cc3..bb7b2128 100644 --- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm +++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -51,7 +51,7 @@ #include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h" #include "ios/chrome/browser/sync/ios_chrome_sync_client.h" #include "ios/chrome/browser/tab_parenting_global_observer.h" -#include "ios/chrome/browser/ui/browser_list_ios.h" +#include "ios/chrome/browser/tabs/tab_model_list.h" #include "ios/chrome/common/channel_info.h" #include "ios/web/public/web_thread.h" @@ -193,7 +193,7 @@ // be worth revisiting this to still log events from non-incognito sessions. metrics_service_->RegisterMetricsProvider( base::MakeUnique<OmniboxMetricsProvider>( - base::Bind(&BrowserListIOS::IsOffTheRecordSessionActive))); + base::Bind(&::IsOffTheRecordSessionActive))); { auto stability_metrics_provider =
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm index d528c47..9d4cf92 100644 --- a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm +++ b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
@@ -16,7 +16,7 @@ #include "ios/chrome/browser/chrome_switches.h" #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_accessor.h" #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h" -#include "ios/chrome/browser/ui/browser_list_ios.h" +#include "ios/chrome/browser/tabs/tab_model_list.h" #include "ios/chrome/browser/variations/ios_chrome_variations_service_client.h" #include "ios/chrome/browser/variations/ios_ui_string_overrider_factory.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" @@ -63,7 +63,7 @@ IOSChromeMetricsServicesManagerClient::CreateRapporServiceImpl() { DCHECK(thread_checker_.CalledOnValidThread()); return base::MakeUnique<rappor::RapporServiceImpl>( - local_state_, base::Bind(&BrowserListIOS::IsOffTheRecordSessionActive)); + local_state_, base::Bind(&::IsOffTheRecordSessionActive)); } std::unique_ptr<variations::VariationsService>
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.mm b/ios/chrome/browser/metrics/new_tab_page_uma.mm index 48fe6db..47375cc 100644 --- a/ios/chrome/browser/metrics/new_tab_page_uma.mm +++ b/ios/chrome/browser/metrics/new_tab_page_uma.mm
@@ -10,16 +10,15 @@ #include "ios/chrome/browser/chrome_url_constants.h" #import "ios/chrome/browser/tabs/tab.h" #import "ios/chrome/browser/tabs/tab_model.h" -#import "ios/chrome/browser/ui/browser_list_ios.h" +#import "ios/chrome/browser/tabs/tab_model_list.h" #include "url/gurl.h" namespace new_tab_page_uma { bool IsCurrentlyOnNTP(ios::ChromeBrowserState* browserState) { - Tab* currentTab = - [[BrowserListIOS::GetLastActiveWithBrowserState(browserState) tabModel] - currentTab]; - return currentTab && currentTab.url == GURL(kChromeUINewTabURL); + TabModel* tabModel = GetLastActiveTabModelForChromeBrowserState(browserState); + return tabModel.currentTab && + tabModel.currentTab.url == GURL(kChromeUINewTabURL); } void RecordAction(ios::ChromeBrowserState* browserState, ActionType type) {
diff --git a/ios/chrome/browser/omaha/BUILD.gn b/ios/chrome/browser/omaha/BUILD.gn index b21d3e9..8d5eb217 100644 --- a/ios/chrome/browser/omaha/BUILD.gn +++ b/ios/chrome/browser/omaha/BUILD.gn
@@ -15,7 +15,7 @@ "//components/profile_metrics", "//components/version_info", "//ios/chrome/browser", - "//ios/chrome/browser/browser_state:browser_state_impl", + "//ios/chrome/browser/browser_state", "//ios/chrome/browser/browser_state_metrics", "//ios/chrome/browser/ui", "//ios/chrome/browser/upgrade",
diff --git a/ios/chrome/browser/payments/payment_request_manager.mm b/ios/chrome/browser/payments/payment_request_manager.mm index b3565d7..0673ad7 100644 --- a/ios/chrome/browser/payments/payment_request_manager.mm +++ b/ios/chrome/browser/payments/payment_request_manager.mm
@@ -203,10 +203,12 @@ } - (void)initializeWebViewForPaymentRequest { - DCHECK(_webStateEnabled); + if (_enabled) { + DCHECK(_webStateEnabled); - [_paymentRequestJsManager inject]; - _isScriptInjected = YES; + [_paymentRequestJsManager inject]; + _isScriptInjected = YES; + } } - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand { @@ -319,10 +321,10 @@ - (void)webState:(web::WebState*)webState didCommitNavigationWithDetails: (const web::LoadCommittedDetails&)load_details { - _isScriptInjected = NO; [self dismissUI]; - [self initializeWebViewForPaymentRequest]; + _isScriptInjected = NO; [self enableCurrentWebState]; + [self initializeWebViewForPaymentRequest]; } @end
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.cc b/ios/chrome/browser/reading_list/offline_url_utils.cc index 5ce022c..22d93421 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils.cc +++ b/ios/chrome/browser/reading_list/offline_url_utils.cc
@@ -66,27 +66,4 @@ bool IsOfflineURL(const GURL& url) { return url.SchemeIs(kChromeUIScheme) && url.host() == kChromeUIOfflineHost; } - -base::string16 StripSchemeFromOnlineURL(const base::string16& online_url, - size_t* removed_chars) { - base::string16 https_scheme = base::UTF8ToUTF16(base::StringPrintf( - "%s%s", url::kHttpsScheme, url::kStandardSchemeSeparator)); - if (base::StartsWith(online_url, https_scheme, - base::CompareCase::SENSITIVE)) { - if (removed_chars) { - *removed_chars = https_scheme.length(); - } - return online_url.substr(https_scheme.length()); - } - // http:// scheme should already have been trimmed at this point. - // DCHECK to detect formatting changes in omnibox. - DCHECK(!base::StartsWith( - online_url, base::UTF8ToUTF16(base::StringPrintf( - "%s%s", url::kHttpScheme, url::kStandardSchemeSeparator)), - base::CompareCase::SENSITIVE)); - if (removed_chars) { - *removed_chars = 0; - } - return online_url; -} }
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.h b/ios/chrome/browser/reading_list/offline_url_utils.h index 1904840..c2c0dcc 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils.h +++ b/ios/chrome/browser/reading_list/offline_url_utils.h
@@ -31,13 +31,6 @@ // Returns whether the URL points to a chrome offline URL. bool IsOfflineURL(const GURL& url); -// Strips scheme from the original URL of the offline page. This is meant to be -// used by UI. -// If |removed_chars| is non-NULL, it is set to the number of chars that have -// been removed at the begining of |online_url|. -base::string16 StripSchemeFromOnlineURL(const base::string16& online_url, - size_t* removed_chars); - } // namespace reading_list #endif // IOS_CHROME_BROWSER_READING_LIST_OFFLINE_URL_UTILS_H_
diff --git a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc index 3f794d3..e8b5ee2 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc +++ b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
@@ -84,34 +84,3 @@ reading_list::IsOfflineURL(GURL("chrome://offline/foobar?foo=bar"))); } -// Checks that https:// scheme is correctly removed by -// StripSchemeFromOnlineURLTest. -TEST(OfflineURLUtilsTest, StripSchemeFromOnlineURLTest) { - size_t removed_size; - base::string16 empty_url; - EXPECT_EQ(reading_list::StripSchemeFromOnlineURL(empty_url, &removed_size), - empty_url); - EXPECT_EQ(removed_size, 0u); - - base::string16 https_url = base::UTF8ToUTF16("https://www.chromium.org/"); - base::string16 trimmed_https_url = base::UTF8ToUTF16("www.chromium.org/"); - EXPECT_EQ(reading_list::StripSchemeFromOnlineURL(https_url, &removed_size), - trimmed_https_url); - EXPECT_EQ(removed_size, 8u); - base::string16 http_url = base::UTF8ToUTF16("http://www.chromium.org/"); - EXPECT_DCHECK_DEATH( - reading_list::StripSchemeFromOnlineURL(http_url, &removed_size)); - - base::string16 other_scheme_url = - base::UTF8ToUTF16("scheme://www.chromium.org/"); - EXPECT_EQ( - reading_list::StripSchemeFromOnlineURL(other_scheme_url, &removed_size), - other_scheme_url); - EXPECT_EQ(removed_size, 0u); - - base::string16 no_scheme_url = base::UTF8ToUTF16("www.chromium.org/"); - EXPECT_EQ( - reading_list::StripSchemeFromOnlineURL(no_scheme_url, &removed_size), - no_scheme_url); - EXPECT_EQ(removed_size, 0u); -}
diff --git a/ios/chrome/browser/reading_list/reading_list_download_service.cc b/ios/chrome/browser/reading_list/reading_list_download_service.cc index 07bddca..f3337a7 100644 --- a/ios/chrome/browser/reading_list/reading_list_download_service.cc +++ b/ios/chrome/browser/reading_list/reading_list_download_service.cc
@@ -94,7 +94,8 @@ void ReadingListDownloadService::ReadingListDidAddEntry( const ReadingListModel* model, - const GURL& url) { + const GURL& url, + reading_list::EntrySource source) { DCHECK_EQ(reading_list_model_, model); ProcessNewEntry(url); }
diff --git a/ios/chrome/browser/reading_list/reading_list_download_service.h b/ios/chrome/browser/reading_list/reading_list_download_service.h index 55adb74..27cfed8c 100644 --- a/ios/chrome/browser/reading_list/reading_list_download_service.h +++ b/ios/chrome/browser/reading_list/reading_list_download_service.h
@@ -58,7 +58,8 @@ void ReadingListWillRemoveEntry(const ReadingListModel* model, const GURL& url) override; void ReadingListDidAddEntry(const ReadingListModel* model, - const GURL& url) override; + const GURL& url, + reading_list::EntrySource entry_source) override; void ReadingListDidMoveEntry(const ReadingListModel* model, const GURL& url) override;
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm index 45c0e45..4f30e28 100644 --- a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm +++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
@@ -56,7 +56,8 @@ test_web_state_.SetNavigationManager(std::move(test_navigation_manager)); reading_list_model_ = base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); - reading_list_model_->AddEntry(GURL(kTestURL), kTestTitle); + reading_list_model_->AddEntry(GURL(kTestURL), kTestTitle, + reading_list::ADDED_VIA_CURRENT_APP); ReadingListWebStateObserver::FromWebState(&test_web_state_, reading_list_model_.get()); }
diff --git a/ios/chrome/browser/sessions/BUILD.gn b/ios/chrome/browser/sessions/BUILD.gn index a3d954c..cf8b95d 100644 --- a/ios/chrome/browser/sessions/BUILD.gn +++ b/ios/chrome/browser/sessions/BUILD.gn
@@ -19,7 +19,6 @@ "//ios/chrome/browser", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/tabs", - "//ios/chrome/browser/ui:browser_list", "//ios/public/provider/chrome/browser", "//ios/web", "//url", @@ -52,7 +51,6 @@ "//components/sessions", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/tabs", - "//ios/chrome/browser/ui:browser_list", "//ios/web", "//net", ]
diff --git a/ios/chrome/browser/sessions/ios_chrome_tab_restore_service_client.mm b/ios/chrome/browser/sessions/ios_chrome_tab_restore_service_client.mm index 3856953..f8f47ec 100644 --- a/ios/chrome/browser/sessions/ios_chrome_tab_restore_service_client.mm +++ b/ios/chrome/browser/sessions/ios_chrome_tab_restore_service_client.mm
@@ -4,15 +4,18 @@ #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_client.h" +#include "base/bind.h" +#include "base/callback.h" #include "components/sessions/ios/ios_live_tab.h" +#include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h" -#include "ios/chrome/browser/tabs/tab.h" -#include "ios/chrome/browser/tabs/tab_model.h" -#include "ios/chrome/browser/ui/browser_ios.h" -#include "ios/chrome/browser/ui/browser_list_ios.h" +#import "ios/chrome/browser/tabs/tab.h" +#import "ios/chrome/browser/tabs/tab_model.h" +#import "ios/chrome/browser/tabs/tab_model_list.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "ios/web/public/web_thread.h" #include "url/gurl.h" @@ -21,6 +24,45 @@ #error "This file requires ARC support." #endif +namespace { +sessions::LiveTabContext* FindLiveTabContextWithCondition( + const base::Callback<bool(TabModel*)>& condition) { + std::vector<ios::ChromeBrowserState*> browser_states = + GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetLoadedBrowserStates(); + + for (ios::ChromeBrowserState* browser_state : browser_states) { + DCHECK(!browser_state->IsOffTheRecord()); + NSArray<TabModel*>* tab_models; + + tab_models = GetTabModelsForChromeBrowserState(browser_state); + for (TabModel* tab_model : tab_models) { + if (condition.Run(tab_model)) { + return TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState( + browser_state); + } + } + + if (!browser_state->HasOffTheRecordChromeBrowserState()) + continue; + + ios::ChromeBrowserState* otr_browser_state = + browser_state->GetOffTheRecordChromeBrowserState(); + + tab_models = GetTabModelsForChromeBrowserState(otr_browser_state); + for (TabModel* tab_model : tab_models) { + if (condition.Run(tab_model)) { + return TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState( + browser_state); + } + } + } + + return nullptr; +} +} // namespace + IOSChromeTabRestoreServiceClient::IOSChromeTabRestoreServiceClient( ios::ChromeBrowserState* browser_state) : browser_state_(browser_state) {} @@ -39,32 +81,27 @@ const sessions::LiveTab* tab) { const sessions::IOSLiveTab* requested_tab = static_cast<const sessions::IOSLiveTab*>(tab); - for (BrowserListIOS::const_iterator iter = BrowserListIOS::begin(); - iter != BrowserListIOS::end(); ++iter) { - id<BrowserIOS> browser = *iter; - for (Tab* current_tab in [browser tabModel]) { - if (current_tab.webState && - current_tab.webState == requested_tab->web_state()) { - return TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState( - [browser browserState]); - } - } - } - return nullptr; + + return FindLiveTabContextWithCondition(base::Bind( + [](const web::WebState* web_state, TabModel* tab_model) { + for (Tab* current_tab in tab_model) { + if (current_tab.webState && current_tab.webState == web_state) { + return true; + } + } + return false; + }, + requested_tab->web_state())); } sessions::LiveTabContext* IOSChromeTabRestoreServiceClient::FindLiveTabContextWithID( SessionID::id_type desired_id) { - for (BrowserListIOS::const_iterator iter = BrowserListIOS::begin(); - iter != BrowserListIOS::end(); ++iter) { - id<BrowserIOS> browser = *iter; - if ([browser tabModel].sessionID.id() == desired_id) { - return TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState( - [browser browserState]); - } - } - return nullptr; + return FindLiveTabContextWithCondition(base::Bind( + [](SessionID::id_type desired_id, TabModel* tab_model) { + return tab_model.sessionID.id() == desired_id; + }, + desired_id)); } bool IOSChromeTabRestoreServiceClient::ShouldTrackURLForRestore(
diff --git a/ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.mm b/ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.mm index 160bdd4f..ce78267 100644 --- a/ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.mm +++ b/ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.mm
@@ -14,8 +14,7 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/tabs/tab.h" #import "ios/chrome/browser/tabs/tab_model.h" -#include "ios/chrome/browser/ui/browser_ios.h" -#include "ios/chrome/browser/ui/browser_list_ios.h" +#import "ios/chrome/browser/tabs/tab_model_list.h" #import "ios/web/navigation/navigation_manager_impl.h" #include "ios/web/public/navigation_item.h" #import "ios/web/web_state/web_state_impl.h" @@ -30,9 +29,7 @@ TabRestoreServiceDelegateImplIOS::~TabRestoreServiceDelegateImplIOS() {} TabModel* TabRestoreServiceDelegateImplIOS::tab_model() const { - id<BrowserIOS> browser = - BrowserListIOS::GetLastActiveWithBrowserState(browser_state_); - return [browser tabModel]; + return GetLastActiveTabModelForChromeBrowserState(browser_state_); } void TabRestoreServiceDelegateImplIOS::ShowBrowserWindow() {
diff --git a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm index 3b615ec..2a2d88a 100644 --- a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm +++ b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
@@ -214,8 +214,9 @@ [entryType integerValue]); if (type == app_group::READING_LIST_ITEM) { LogHistogramReceivedItem(READINGLIST_ENTRY); - _readingListModel->AddEntry(entryURL, - entryTitle); + _readingListModel->AddEntry( + entryURL, entryTitle, + reading_list::ADDED_VIA_EXTENSION); } if (type == app_group::BOOKMARK_ITEM) { LogHistogramReceivedItem(BOOKMARK_ENTRY);
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 10bf741..cd740bcd 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -79,8 +79,7 @@ explicit SyncSessionsClientImpl(ios::ChromeBrowserState* browser_state) : browser_state_(browser_state), window_delegates_getter_( - base::MakeUnique<TabModelSyncedWindowDelegatesGetter>( - browser_state)) {} + base::MakeUnique<TabModelSyncedWindowDelegatesGetter>()) {} ~SyncSessionsClientImpl() override {} @@ -138,7 +137,8 @@ IOSChromeSyncClient::IOSChromeSyncClient(ios::ChromeBrowserState* browser_state) : browser_state_(browser_state), - sync_sessions_client_(new SyncSessionsClientImpl(browser_state)), + sync_sessions_client_( + base::MakeUnique<SyncSessionsClientImpl>(browser_state)), weak_ptr_factory_(this) {} IOSChromeSyncClient::~IOSChromeSyncClient() {}
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn index e667fd4d..8a5b6e5 100644 --- a/ios/chrome/browser/tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -89,7 +89,6 @@ "//ios/chrome/browser/translate", "//ios/chrome/browser/u2f", "//ios/chrome/browser/ui", - "//ios/chrome/browser/ui:browser_list", "//ios/chrome/browser/ui:ui_internal", "//ios/chrome/browser/ui/alert_coordinator", "//ios/chrome/browser/ui/commands", @@ -123,6 +122,7 @@ deps = [ ":tabs", "//base", + "//ios/chrome/browser", "//ios/chrome/browser/browser_state", ] libs = [ "Foundation.framework" ]
diff --git a/ios/chrome/browser/tabs/tab_model_list.h b/ios/chrome/browser/tabs/tab_model_list.h index bbba490..806fbc9 100644 --- a/ios/chrome/browser/tabs/tab_model_list.h +++ b/ios/chrome/browser/tabs/tab_model_list.h
@@ -34,4 +34,12 @@ NSArray<TabModel*>* GetTabModelsForChromeBrowserState( ios::ChromeBrowserState* browser_state); +// Returns the last active TabModel associated with |browser_state|. +TabModel* GetLastActiveTabModelForChromeBrowserState( + ios::ChromeBrowserState* browser_state); + +// Returns true if a incognito session is currently active (i.e. at least +// one incognito tab is open). +bool IsOffTheRecordSessionActive(); + #endif // IOS_CHROME_BROWSER_TABS_TAB_MODEL_LIST_H_
diff --git a/ios/chrome/browser/tabs/tab_model_list.mm b/ios/chrome/browser/tabs/tab_model_list.mm index b9562232..eba1a08 100644 --- a/ios/chrome/browser/tabs/tab_model_list.mm +++ b/ios/chrome/browser/tabs/tab_model_list.mm
@@ -7,7 +7,9 @@ #include "base/logging.h" #include "base/macros.h" #include "base/supports_user_data.h" +#include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" #import "ios/chrome/browser/tabs/tab_model.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -85,3 +87,45 @@ TabModelList::GetForBrowserState(browser_state, false); return tab_model_list ? [tab_model_list->tab_models() allObjects] : nil; } + +TabModel* GetLastActiveTabModelForChromeBrowserState( + ios::ChromeBrowserState* browser_state) { + TabModelList* tab_model_list = + TabModelList::GetForBrowserState(browser_state, false); + if (!tab_model_list || [tab_model_list->tab_models() count] == 0u) + return nil; + + // There is currently no way to mark a TabModel as active. Assert that there + // is only one TabModel associated with |browser_state| until it is possible + // to mark a TabModel as active. + DCHECK_EQ([tab_model_list->tab_models() count], 1u); + return [tab_model_list->tab_models() anyObject]; +} + +bool IsOffTheRecordSessionActive() { + std::vector<ios::ChromeBrowserState*> browser_states = + GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetLoadedBrowserStates(); + + for (ios::ChromeBrowserState* browser_state : browser_states) { + DCHECK(!browser_state->IsOffTheRecord()); + if (!browser_state->HasOffTheRecordChromeBrowserState()) + continue; + + ios::ChromeBrowserState* otr_browser_state = + browser_state->GetOffTheRecordChromeBrowserState(); + + TabModelList* tab_model_list = + TabModelList::GetForBrowserState(otr_browser_state, false); + if (!tab_model_list) + continue; + + for (TabModel* tab_model in tab_model_list->tab_models()) { + if (![tab_model isEmpty]) + return true; + } + } + + return false; +}
diff --git a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm index 9e8701e..1dc244c 100644 --- a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm +++ b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
@@ -11,7 +11,6 @@ #include "ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h" #include "ios/chrome/browser/tabs/tab.h" #include "ios/chrome/browser/tabs/tab_model.h" -#import "ios/chrome/browser/ui/browser_list_ios.h" #import "ios/web/public/web_state/web_state.h" TabModelSyncedWindowDelegate::TabModelSyncedWindowDelegate(TabModel* tab_model)
diff --git a/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h b/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h index 922dce17..728d144 100644 --- a/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h +++ b/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h
@@ -15,28 +15,19 @@ class SyncedWindowDelegate; } -namespace ios { -class ChromeBrowserState; -} - class TabModelSyncedWindowDelegatesGetter : public sync_sessions::SyncedWindowDelegatesGetter { public: - // TODO(crbug.com/548612): |browser_state| may be unnecessary as iOS does not - // supports multi-profile starting with M47. Should it be removed? - explicit TabModelSyncedWindowDelegatesGetter( - ios::ChromeBrowserState* browser_state); + TabModelSyncedWindowDelegatesGetter(); ~TabModelSyncedWindowDelegatesGetter() override; // sync_sessions::SyncedWindowDelegatesGetter: std::set<const sync_sessions::SyncedWindowDelegate*> GetSyncedWindowDelegates() override; const sync_sessions::SyncedWindowDelegate* FindById( - SessionID::id_type id) override; + SessionID::id_type session_id) override; private: - const ios::ChromeBrowserState* const browser_state_; - DISALLOW_COPY_AND_ASSIGN(TabModelSyncedWindowDelegatesGetter); };
diff --git a/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.mm b/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.mm index 5362854b..df84d972 100644 --- a/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.mm +++ b/ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.mm
@@ -4,14 +4,15 @@ #include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h" +#include "base/logging.h" +#include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/tabs/tab_model.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#import "ios/chrome/browser/tabs/tab_model.h" +#import "ios/chrome/browser/tabs/tab_model_list.h" #import "ios/chrome/browser/tabs/tab_model_synced_window_delegate.h" -#import "ios/chrome/browser/ui/browser_list_ios.h" -TabModelSyncedWindowDelegatesGetter::TabModelSyncedWindowDelegatesGetter( - ios::ChromeBrowserState* browser_state) - : browser_state_(browser_state) {} +TabModelSyncedWindowDelegatesGetter::TabModelSyncedWindowDelegatesGetter() {} TabModelSyncedWindowDelegatesGetter::~TabModelSyncedWindowDelegatesGetter() {} @@ -19,18 +20,20 @@ TabModelSyncedWindowDelegatesGetter::GetSyncedWindowDelegates() { std::set<const sync_sessions::SyncedWindowDelegate*> synced_window_delegates; - for (BrowserListIOS::const_iterator iter = BrowserListIOS::begin(); - iter != BrowserListIOS::end(); ++iter) { - id<BrowserIOS> browser = *iter; - TabModel* tabModel = [browser tabModel]; - // TODO(crbug.com/548612): BrowserState may be unnecessary as iOS does not - // support multiple profiles starting with M47. There should still be a way - // to filter out Incognito delegates, though. - if (tabModel.browserState != browser_state_) - continue; - // Do not return windows without any tabs, to match desktop. - if ([tabModel currentTab]) - synced_window_delegates.insert([tabModel syncedWindowDelegate]); + std::vector<ios::ChromeBrowserState*> browser_states = + GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetLoadedBrowserStates(); + + for (auto* browser_state : browser_states) { + DCHECK(!browser_state->IsOffTheRecord()); + NSArray<TabModel*>* tabModels = + GetTabModelsForChromeBrowserState(browser_state); + for (TabModel* tabModel in tabModels) { + if (tabModel.currentTab) { + synced_window_delegates.insert([tabModel syncedWindowDelegate]); + } + } } return synced_window_delegates; @@ -38,8 +41,7 @@ const sync_sessions::SyncedWindowDelegate* TabModelSyncedWindowDelegatesGetter::FindById(SessionID::id_type session_id) { - for (const sync_sessions::SyncedWindowDelegate* delegate : - GetSyncedWindowDelegates()) { + for (const auto* delegate : GetSyncedWindowDelegates()) { if (session_id == delegate->GetSessionId()) return delegate; }
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm index 4d2e906..dfb7c664 100644 --- a/ios/chrome/browser/tabs/tab_model_unittest.mm +++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -4,11 +4,13 @@ #import <objc/runtime.h> +#include "base/files/file_path.h" #include "base/mac/scoped_nsautorelease_pool.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h" #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/sessions/session_window.h" @@ -18,6 +20,7 @@ #import "ios/chrome/browser/tabs/tab_model_observer.h" #import "ios/chrome/browser/tabs/tab_private.h" #import "ios/chrome/browser/web/chrome_web_client.h" +#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h" #import "ios/web/navigation/crw_session_controller.h" #import "ios/web/navigation/navigation_manager_impl.h" #import "ios/web/public/navigation_manager.h" @@ -47,17 +50,6 @@ toDirectory:(NSString*)directory; @end -// Trivial objective C class whose unique aim is to be a wrapper of C++ -// classes. -@interface ClassesWrapper : NSObject { - @public - std::unique_ptr<WebStateImpl> _webStateImpl; -} -@end - -@implementation ClassesWrapper -@end - @interface TabTest : Tab - (instancetype)initWithWindowName:(NSString*)windowName @@ -81,7 +73,7 @@ id webControllerMock = [OCMockObject niceMockForClass:[CRWWebController class]]; - std::unique_ptr<WebStateImpl> webStateImpl(new WebStateImpl(browserState)); + auto webStateImpl = base::MakeUnique<WebStateImpl>(browserState); webStateImpl->SetWebController(webControllerMock); webStateImpl->GetNavigationManagerImpl().InitializeSession( windowName, @"opener", NO, -1); @@ -137,50 +129,48 @@ class TabModelTest : public PlatformTest { public: - TabModelTest() : web_client_(base::MakeUnique<ChromeWebClient>()) {} - - protected: - void SetUp() override { + TabModelTest() + : scoped_browser_state_manager_( + base::MakeUnique<TestChromeBrowserStateManager>(base::FilePath())), + web_client_(base::MakeUnique<ChromeWebClient>()) { DCHECK_CURRENTLY_ON(web::WebThread::UI); - PlatformTest::SetUp(); TestChromeBrowserState::Builder test_cbs_builder; chrome_browser_state_ = test_cbs_builder.Build(); - sessionWindow_.reset([[SessionWindowIOS alloc] init]); + session_window_.reset([[SessionWindowIOS alloc] init]); // Create tab model with just a dummy session service so the async state // saving doesn't trigger unless actually wanted. base::scoped_nsobject<TestSessionService> test_service( [[TestSessionService alloc] init]); - tabModel_.reset([[TabModel alloc] - initWithSessionWindow:sessionWindow_.get() + tab_model_.reset([[TabModel alloc] + initWithSessionWindow:session_window_.get() sessionService:test_service browserState:chrome_browser_state_.get()]); - [tabModel_ setWebUsageEnabled:YES]; - [tabModel_ setPrimary:YES]; - tabModelObserver_.reset([[TabModelObserverPong alloc] init]); - [tabModel_ addObserver:tabModelObserver_]; + [tab_model_ setWebUsageEnabled:YES]; + [tab_model_ setPrimary:YES]; + tab_model_observer_.reset([[TabModelObserverPong alloc] init]); + [tab_model_ addObserver:tab_model_observer_]; } - void TearDown() override { - [tabModel_ removeObserver:tabModelObserver_]; - [tabModel_ browserStateDestroyed]; - PlatformTest::TearDown(); + ~TabModelTest() override { + [tab_model_ removeObserver:tab_model_observer_]; + [tab_model_ browserStateDestroyed]; } + protected: Tab* CreateTab(NSString* windowName, double lastVisitedTimestamp) NS_RETURNS_RETAINED { return [[TabTest alloc] initWithWindowName:windowName lastVisitedTimestamp:lastVisitedTimestamp browserState:chrome_browser_state_.get() - tabModel:tabModel_.get()]; + tabModel:tab_model_.get()]; } std::unique_ptr<WebStateImpl> CreateWebState(NSString* windowName, NSString* opener, NSInteger index) { - std::unique_ptr<WebStateImpl> webState( - new WebStateImpl(chrome_browser_state_.get())); + auto webState = base::MakeUnique<WebStateImpl>(chrome_browser_state_.get()); webState->GetNavigationManagerImpl().InitializeSession(windowName, opener, NO, index); return webState; @@ -195,7 +185,7 @@ } void RestoreSession(SessionWindowIOS* window) { - [tabModel_ restoreSessionWindow:window]; + [tab_model_ restoreSessionWindow:window]; } // Creates a session window with |entries| entries and a |selectedIndex| of 1. @@ -211,370 +201,371 @@ } web::TestWebThreadBundle thread_bundle_; + IOSChromeScopedTestingChromeBrowserStateManager scoped_browser_state_manager_; web::ScopedTestingWebClient web_client_; - base::scoped_nsobject<SessionWindowIOS> sessionWindow_; + base::scoped_nsobject<SessionWindowIOS> session_window_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; - base::scoped_nsobject<TabModel> tabModel_; - base::scoped_nsobject<TabModelObserverPong> tabModelObserver_; + base::scoped_nsobject<TabModel> tab_model_; + base::scoped_nsobject<TabModelObserverPong> tab_model_observer_; base::mac::ScopedNSAutoreleasePool pool_; }; TEST_F(TabModelTest, IsEmpty) { - EXPECT_EQ([tabModel_ count], 0U); - EXPECT_TRUE([tabModel_ isEmpty]); - [tabModel_ insertTabWithURL:kURL - referrer:kReferrer - windowName:@"window 1" - opener:nil - atIndex:0]; - ASSERT_EQ(1U, [tabModel_ count]); - EXPECT_FALSE([tabModel_ isEmpty]); + EXPECT_EQ([tab_model_ count], 0U); + EXPECT_TRUE([tab_model_ isEmpty]); + [tab_model_ insertTabWithURL:kURL + referrer:kReferrer + windowName:@"window 1" + opener:nil + atIndex:0]; + ASSERT_EQ(1U, [tab_model_ count]); + EXPECT_FALSE([tab_model_ isEmpty]); } TEST_F(TabModelTest, InsertUrlSingle) { - [tabModel_ insertTabWithURL:kURL - referrer:kReferrer - windowName:@"window 1" - opener:nil - atIndex:0]; - ASSERT_EQ(1U, [tabModel_ count]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); + [tab_model_ insertTabWithURL:kURL + referrer:kReferrer + windowName:@"window 1" + opener:nil + atIndex:0]; + ASSERT_EQ(1U, [tab_model_ count]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); } TEST_F(TabModelTest, InsertUrlMultiple) { - [tabModel_ insertTabWithURL:kURL - referrer:kReferrer - windowName:@"window 1" - opener:nil - atIndex:0]; - [tabModel_ insertTabWithURL:kURL - referrer:kReferrer - windowName:@"window 2" - opener:nil - atIndex:0]; - [tabModel_ insertTabWithURL:kURL - referrer:kReferrer - windowName:@"window 3" - opener:nil - atIndex:1]; + [tab_model_ insertTabWithURL:kURL + referrer:kReferrer + windowName:@"window 1" + opener:nil + atIndex:0]; + [tab_model_ insertTabWithURL:kURL + referrer:kReferrer + windowName:@"window 2" + opener:nil + atIndex:0]; + [tab_model_ insertTabWithURL:kURL + referrer:kReferrer + windowName:@"window 3" + opener:nil + atIndex:1]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:2] windowName]); + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:2] windowName]); } TEST_F(TabModelTest, AppendUrlSingle) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - ASSERT_EQ(1U, [tabModel_ count]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + ASSERT_EQ(1U, [tab_model_ count]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); } TEST_F(TabModelTest, AppendUrlMultiple) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:2] windowName]); + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:2] windowName]); } TEST_F(TabModelTest, CloseTabAtIndexBeginning) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - [tabModel_ closeTabAtIndex:0]; + [tab_model_ closeTabAtIndex:0]; - ASSERT_EQ(2U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); + ASSERT_EQ(2U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); } TEST_F(TabModelTest, CloseTabAtIndexMiddle) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - [tabModel_ closeTabAtIndex:1]; + [tab_model_ closeTabAtIndex:1]; - ASSERT_EQ(2U, [tabModel_ count]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); + ASSERT_EQ(2U, [tab_model_ count]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); } TEST_F(TabModelTest, CloseTabAtIndexLast) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - [tabModel_ closeTabAtIndex:2]; + [tab_model_ closeTabAtIndex:2]; - ASSERT_EQ(2U, [tabModel_ count]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:1] windowName]); + ASSERT_EQ(2U, [tab_model_ count]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:1] windowName]); } TEST_F(TabModelTest, CloseTabAtIndexOnlyOne) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ closeTabAtIndex:0]; + [tab_model_ closeTabAtIndex:0]; - EXPECT_EQ(0U, [tabModel_ count]); + EXPECT_EQ(0U, [tab_model_ count]); } TEST_F(TabModelTest, RestoreSessionOnNTPTest) { - [tabModel_ insertTabWithURL:GURL(kChromeUINewTabURL) - referrer:kEmptyReferrer - windowName:@"old window" - opener:nil - atIndex:0]; + [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL) + referrer:kEmptyReferrer + windowName:@"old window" + opener:nil + atIndex:0]; base::scoped_nsobject<SessionWindowIOS> window(CreateSessionWindow(3)); RestoreSession(window.get()); - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ currentTab] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:2] windowName]); + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ currentTab] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:2] windowName]); } TEST_F(TabModelTest, RestoreSessionOn2NtpTest) { - [tabModel_ insertTabWithURL:GURL(kChromeUINewTabURL) - referrer:kEmptyReferrer - windowName:@"old window 1" - opener:nil - atIndex:0]; - [tabModel_ insertTabWithURL:GURL(kChromeUINewTabURL) - referrer:kEmptyReferrer - windowName:@"old window 2" - opener:nil - atIndex:1]; + [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL) + referrer:kEmptyReferrer + windowName:@"old window 1" + opener:nil + atIndex:0]; + [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL) + referrer:kEmptyReferrer + windowName:@"old window 2" + opener:nil + atIndex:1]; base::scoped_nsobject<SessionWindowIOS> window(CreateSessionWindow(3)); RestoreSession(window.get()); - ASSERT_EQ(5U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ currentTab] windowName]); - EXPECT_NSEQ(@"old window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"old window 2", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:3] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:4] windowName]); + ASSERT_EQ(5U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ currentTab] windowName]); + EXPECT_NSEQ(@"old window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"old window 2", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:3] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:4] windowName]); } TEST_F(TabModelTest, RestoreSessionOnAnyTest) { - [tabModel_ insertTabWithURL:kURL - referrer:kEmptyReferrer - windowName:@"old window 1" - opener:nil - atIndex:0]; + [tab_model_ insertTabWithURL:kURL + referrer:kEmptyReferrer + windowName:@"old window 1" + opener:nil + atIndex:0]; base::scoped_nsobject<SessionWindowIOS> window(CreateSessionWindow(3)); RestoreSession(window.get()); - ASSERT_EQ(4U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ currentTab] windowName]); - EXPECT_NSEQ(@"old window 1", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:3] windowName]); + ASSERT_EQ(4U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ currentTab] windowName]); + EXPECT_NSEQ(@"old window 1", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:3] windowName]); } TEST_F(TabModelTest, TabForWindowName) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:GURL("https://www.some.url2.com") - referrer:kReferrer2 - windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:GURL("https://www.some.url2.com") + referrer:kReferrer2 + windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - Tab* tab = [tabModel_ tabWithWindowName:@"window 2"]; + Tab* tab = [tab_model_ tabWithWindowName:@"window 2"]; EXPECT_NSEQ([tab windowName], @"window 2"); EXPECT_EQ(tab.url, GURL("https://www.some.url2.com/")); } TEST_F(TabModelTest, TabForWindowNameNotFound) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:GURL("https://www.some.url2.com") - referrer:kReferrer2 - windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:GURL("https://www.some.url2.com") + referrer:kReferrer2 + windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - Tab* tab = [tabModel_ tabWithWindowName:@"window not found"]; + Tab* tab = [tab_model_ tabWithWindowName:@"window not found"]; EXPECT_EQ(nil, tab); } TEST_F(TabModelTest, CloseAllTabs) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:GURL("https://www.some.url2.com") - referrer:kReferrer2 - windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:GURL("https://www.some.url2.com") + referrer:kReferrer2 + windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; - [tabModel_ closeAllTabs]; + [tab_model_ closeAllTabs]; - EXPECT_EQ(0U, [tabModel_ count]); + EXPECT_EQ(0U, [tab_model_ count]); } TEST_F(TabModelTest, CloseAllTabsWithNoTabs) { - [tabModel_ closeAllTabs]; + [tab_model_ closeAllTabs]; - EXPECT_EQ(0U, [tabModel_ count]); + EXPECT_EQ(0U, [tab_model_ count]); } TEST_F(TabModelTest, InsertWithSessionController) { - EXPECT_EQ([tabModel_ count], 0U); - EXPECT_TRUE([tabModel_ isEmpty]); + EXPECT_EQ([tab_model_ count], 0U); + EXPECT_TRUE([tab_model_ isEmpty]); Tab* new_tab = - [tabModel_ insertTabWithWebState:CreateWebState(@"window", @"opener", -1) - atIndex:0]; - EXPECT_EQ([tabModel_ count], 1U); - [tabModel_ setCurrentTab:new_tab]; - Tab* current_tab = [tabModel_ currentTab]; + [tab_model_ insertTabWithWebState:CreateWebState(@"window", @"opener", -1) + atIndex:0]; + EXPECT_EQ([tab_model_ count], 1U); + [tab_model_ setCurrentTab:new_tab]; + Tab* current_tab = [tab_model_ currentTab]; EXPECT_TRUE(current_tab); } TEST_F(TabModelTest, OpenerOfTab) { // Start off with a couple tabs. - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // Create parent tab. - Tab* parent_tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* parent_tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; // Create child tab. Tab* child_tab = - [tabModel_ insertTabWithWebState:CreateChildWebState(parent_tab) - atIndex:[tabModel_ count]]; + [tab_model_ insertTabWithWebState:CreateChildWebState(parent_tab) + atIndex:[tab_model_ count]]; // Create another unrelated tab. - Tab* another_tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* another_tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; // Create another child of the first tab. Tab* child_tab2 = - [tabModel_ insertTabWithWebState:CreateChildWebState(parent_tab) - atIndex:[tabModel_ count]]; + [tab_model_ insertTabWithWebState:CreateChildWebState(parent_tab) + atIndex:[tab_model_ count]]; - EXPECT_FALSE([tabModel_ openerOfTab:parent_tab]); - EXPECT_FALSE([tabModel_ openerOfTab:another_tab]); - EXPECT_EQ(parent_tab, [tabModel_ openerOfTab:child_tab]); - EXPECT_EQ(parent_tab, [tabModel_ openerOfTab:child_tab2]); + EXPECT_FALSE([tab_model_ openerOfTab:parent_tab]); + EXPECT_FALSE([tab_model_ openerOfTab:another_tab]); + EXPECT_EQ(parent_tab, [tab_model_ openerOfTab:child_tab]); + EXPECT_EQ(parent_tab, [tab_model_ openerOfTab:child_tab2]); } TEST_F(TabModelTest, OpenerOfTabEmptyModel) { - EXPECT_FALSE([tabModel_ openerOfTab:nil]); + EXPECT_FALSE([tab_model_ openerOfTab:nil]); } TEST_F(TabModelTest, OpenersEmptyModel) { // Empty model. - EXPECT_TRUE([tabModel_ isEmpty]); - EXPECT_FALSE([tabModel_ nextTabWithOpener:nil afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:nil]); - EXPECT_FALSE([tabModel_ firstTabWithOpener:nil]); + EXPECT_TRUE([tab_model_ isEmpty]); + EXPECT_FALSE([tab_model_ nextTabWithOpener:nil afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:nil]); + EXPECT_FALSE([tab_model_ firstTabWithOpener:nil]); } TEST_F(TabModelTest, OpenersNothingOpenedGeneral) { // Start with a few tabs. - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - Tab* tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // All should fail since this hasn't opened anything else. - EXPECT_FALSE([tabModel_ nextTabWithOpener:tab afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:tab]); - EXPECT_FALSE([tabModel_ firstTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ nextTabWithOpener:tab afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ firstTabWithOpener:tab]); // Add more items to the tab, expect the same results. - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - EXPECT_FALSE([tabModel_ nextTabWithOpener:tab afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:tab]); - EXPECT_FALSE([tabModel_ firstTabWithOpener:tab]); + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + EXPECT_FALSE([tab_model_ nextTabWithOpener:tab afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ firstTabWithOpener:tab]); } TEST_F(TabModelTest, OpenersNothingOpenedFirst) { // Our tab is first. - Tab* tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // All should fail since this hasn't opened anything else. - EXPECT_FALSE([tabModel_ nextTabWithOpener:tab afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:tab]); - EXPECT_FALSE([tabModel_ firstTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ nextTabWithOpener:tab afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ firstTabWithOpener:tab]); } TEST_F(TabModelTest, OpenersNothingOpenedLast) { // Our tab is last. - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - Tab* tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + Tab* tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; // All should fail since this hasn't opened anything else. - EXPECT_FALSE([tabModel_ nextTabWithOpener:tab afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:tab]); - EXPECT_FALSE([tabModel_ firstTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ nextTabWithOpener:tab afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:tab]); + EXPECT_FALSE([tab_model_ firstTabWithOpener:tab]); } TEST_F(TabModelTest, OpenersChildTabBeforeOpener) { - Tab* parent_tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* parent_tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; // Insert child at start Tab* child_tab = - [tabModel_ insertTabWithWebState:CreateChildWebState(parent_tab) - atIndex:0]; + [tab_model_ insertTabWithWebState:CreateChildWebState(parent_tab) + atIndex:0]; // Insert a few more between them. - [tabModel_ insertTabWithWebState:CreateWebState(@"window") atIndex:1]; - [tabModel_ insertTabWithWebState:CreateWebState(@"window") atIndex:1]; + [tab_model_ insertTabWithWebState:CreateWebState(@"window") atIndex:1]; + [tab_model_ insertTabWithWebState:CreateWebState(@"window") atIndex:1]; - EXPECT_FALSE([tabModel_ nextTabWithOpener:parent_tab afterTab:nil]); - EXPECT_FALSE([tabModel_ lastTabWithOpener:parent_tab]); - EXPECT_EQ([tabModel_ firstTabWithOpener:parent_tab], child_tab); + EXPECT_FALSE([tab_model_ nextTabWithOpener:parent_tab afterTab:nil]); + EXPECT_FALSE([tab_model_ lastTabWithOpener:parent_tab]); + EXPECT_EQ([tab_model_ firstTabWithOpener:parent_tab], child_tab); } TEST_F(TabModelTest, OpenersChildTabAfterOpener) { - Tab* parent_tab = [tabModel_ insertTabWithWebState:CreateWebState(@"window") - atIndex:[tabModel_ count]]; + Tab* parent_tab = [tab_model_ insertTabWithWebState:CreateWebState(@"window") + atIndex:[tab_model_ count]]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // Insert two children at end. Tab* child_tab1 = - [tabModel_ insertTabWithWebState:CreateChildWebState(parent_tab) - atIndex:[tabModel_ count]]; + [tab_model_ insertTabWithWebState:CreateChildWebState(parent_tab) + atIndex:[tab_model_ count]]; Tab* child_tab2 = - [tabModel_ insertTabWithWebState:CreateChildWebState(parent_tab) - atIndex:[tabModel_ count]]; + [tab_model_ insertTabWithWebState:CreateChildWebState(parent_tab) + atIndex:[tab_model_ count]]; - EXPECT_EQ([tabModel_ nextTabWithOpener:parent_tab afterTab:nil], child_tab1); - EXPECT_EQ([tabModel_ nextTabWithOpener:parent_tab afterTab:child_tab1], + EXPECT_EQ([tab_model_ nextTabWithOpener:parent_tab afterTab:nil], child_tab1); + EXPECT_EQ([tab_model_ nextTabWithOpener:parent_tab afterTab:child_tab1], child_tab2); - EXPECT_EQ([tabModel_ lastTabWithOpener:parent_tab], child_tab2); - EXPECT_FALSE([tabModel_ firstTabWithOpener:parent_tab]); + EXPECT_EQ([tab_model_ lastTabWithOpener:parent_tab], child_tab2); + EXPECT_FALSE([tab_model_ firstTabWithOpener:parent_tab]); } TEST_F(TabModelTest, AddWithOrderController) { // Create a few tabs with the controller at the front. Tab* parent = - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // Add a new tab, it should be added behind the parent. - Tab* child = [tabModel_ + Tab* child = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -583,11 +574,11 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 0U); - EXPECT_EQ([tabModel_ indexOfTab:child], 1U); + EXPECT_EQ([tab_model_ indexOfTab:parent], 0U); + EXPECT_EQ([tab_model_ indexOfTab:child], 1U); // Add another new tab without a parent, should go at the end. - Tab* tab = [tabModel_ + Tab* tab = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -596,21 +587,21 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:tab], [tabModel_ count] - 1); + EXPECT_EQ([tab_model_ indexOfTab:tab], [tab_model_ count] - 1); // Same for a tab that's not opened via a LINK transition. - Tab* tab2 = [tabModel_ insertOrUpdateTabWithURL:kURL - referrer:kEmptyReferrer - transition:ui::PAGE_TRANSITION_TYPED - windowName:nil - opener:nil - openedByDOM:NO - atIndex:[tabModel_ count] - inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:tab2], [tabModel_ count] - 1); + Tab* tab2 = [tab_model_ insertOrUpdateTabWithURL:kURL + referrer:kEmptyReferrer + transition:ui::PAGE_TRANSITION_TYPED + windowName:nil + opener:nil + openedByDOM:NO + atIndex:[tab_model_ count] + inBackground:NO]; + EXPECT_EQ([tab_model_ indexOfTab:tab2], [tab_model_ count] - 1); // Add a tab in the background. It should appear behind the opening tab. - Tab* tab3 = [tabModel_ + Tab* tab3 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -619,10 +610,10 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:YES]; - EXPECT_EQ([tabModel_ indexOfTab:tab3], [tabModel_ indexOfTab:tab] + 1); + EXPECT_EQ([tab_model_ indexOfTab:tab3], [tab_model_ indexOfTab:tab] + 1); // Add another background tab behind the one we just opened. - Tab* tab4 = [tabModel_ + Tab* tab4 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -631,23 +622,23 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:YES]; - EXPECT_EQ([tabModel_ indexOfTab:tab4], [tabModel_ indexOfTab:tab3] + 1); + EXPECT_EQ([tab_model_ indexOfTab:tab4], [tab_model_ indexOfTab:tab3] + 1); } TEST_F(TabModelTest, AddWithOrderControllerAndGrouping) { // Create a few tabs with the controller at the front. Tab* parent = - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // Force the history to update, as it is used to determine grouping. ASSERT_TRUE([parent navigationManager]); [[parent navigationManager]->GetSessionController() commitPendingEntry]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; ASSERT_TRUE(chrome_browser_state_->CreateHistoryService(true)); // Add a new tab, it should be added behind the parent. - Tab* child1 = [tabModel_ + Tab* child1 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -656,12 +647,12 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 0U); - EXPECT_EQ([tabModel_ indexOfTab:child1], 1U); + EXPECT_EQ([tab_model_ indexOfTab:parent], 0U); + EXPECT_EQ([tab_model_ indexOfTab:child1], 1U); // Add a second child tab in the background. It should be added behind the // first child. - Tab* child2 = [tabModel_ + Tab* child2 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -670,7 +661,7 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:YES]; - EXPECT_EQ([tabModel_ indexOfTab:child2], 2U); + EXPECT_EQ([tab_model_ indexOfTab:child2], 2U); // Navigate the parent tab to a new URL. It should not change any ordering. web::NavigationManager::WebLoadParams parent_params( @@ -679,11 +670,11 @@ [[parent webController] loadWithParams:parent_params]; ASSERT_TRUE([parent navigationManager]); [[parent navigationManager]->GetSessionController() commitPendingEntry]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 0U); + EXPECT_EQ([tab_model_ indexOfTab:parent], 0U); // Add a new tab. It should be added behind the parent. It should not be added // after the previous two children. - Tab* child3 = [tabModel_ + Tab* child3 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -692,11 +683,11 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:child3], 1U); + EXPECT_EQ([tab_model_ indexOfTab:child3], 1U); // Add a fourt child tab in the background. It should be added behind the // third child. - Tab* child4 = [tabModel_ + Tab* child4 = [tab_model_ insertOrUpdateTabWithURL:kURL referrer:kEmptyReferrer transition:ui::PAGE_TRANSITION_LINK @@ -705,128 +696,128 @@ openedByDOM:NO atIndex:TabModelConstants::kTabPositionAutomatically inBackground:YES]; - EXPECT_EQ([tabModel_ indexOfTab:child4], 2U); + EXPECT_EQ([tab_model_ indexOfTab:child4], 2U); // The first two children should have been moved to the right. - EXPECT_EQ([tabModel_ indexOfTab:child1], 3U); - EXPECT_EQ([tabModel_ indexOfTab:child2], 4U); + EXPECT_EQ([tab_model_ indexOfTab:child1], 3U); + EXPECT_EQ([tab_model_ indexOfTab:child2], 4U); // Now add a non-owned tab and make sure it is added at the end. Tab* nonChild = - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - EXPECT_EQ([tabModel_ indexOfTab:nonChild], [tabModel_ count] - 1); + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + EXPECT_EQ([tab_model_ indexOfTab:nonChild], [tab_model_ count] - 1); } TEST_F(TabModelTest, AddWithLinkTransitionAndIndex) { // Create a few tabs with the controller at the front. Tab* parent = - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; // Force the history to update, as it is used to determine grouping. ASSERT_TRUE([parent navigationManager]); [[parent navigationManager]->GetSessionController() commitPendingEntry]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; - [tabModel_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; + [tab_model_ addTabWithURL:kURL referrer:kEmptyReferrer windowName:nil]; ASSERT_TRUE(chrome_browser_state_->CreateHistoryService(true)); // Add a new tab, it should be added before the parent since the index // parameter has been specified with a valid value. - Tab* child1 = [tabModel_ insertOrUpdateTabWithURL:kURL - referrer:kEmptyReferrer - transition:ui::PAGE_TRANSITION_LINK - windowName:nil - opener:parent - openedByDOM:NO - atIndex:0 - inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 1U); - EXPECT_EQ([tabModel_ indexOfTab:child1], 0U); + Tab* child1 = [tab_model_ insertOrUpdateTabWithURL:kURL + referrer:kEmptyReferrer + transition:ui::PAGE_TRANSITION_LINK + windowName:nil + opener:parent + openedByDOM:NO + atIndex:0 + inBackground:NO]; + EXPECT_EQ([tab_model_ indexOfTab:parent], 1U); + EXPECT_EQ([tab_model_ indexOfTab:child1], 0U); // Add a new tab, it should be added at the beginning of the stack because // the index parameter has been specified with a valid value. - Tab* child2 = [tabModel_ insertOrUpdateTabWithURL:kURL - referrer:kEmptyReferrer - transition:ui::PAGE_TRANSITION_LINK - windowName:nil - opener:parent - openedByDOM:NO - atIndex:0 - inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 2U); - EXPECT_EQ([tabModel_ indexOfTab:child1], 1U); - EXPECT_EQ([tabModel_ indexOfTab:child2], 0U); + Tab* child2 = [tab_model_ insertOrUpdateTabWithURL:kURL + referrer:kEmptyReferrer + transition:ui::PAGE_TRANSITION_LINK + windowName:nil + opener:parent + openedByDOM:NO + atIndex:0 + inBackground:NO]; + EXPECT_EQ([tab_model_ indexOfTab:parent], 2U); + EXPECT_EQ([tab_model_ indexOfTab:child1], 1U); + EXPECT_EQ([tab_model_ indexOfTab:child2], 0U); // Add a new tab, it should be added at position 1 because the index parameter // has been specified with a valid value. - Tab* child3 = [tabModel_ insertOrUpdateTabWithURL:kURL - referrer:kEmptyReferrer - transition:ui::PAGE_TRANSITION_LINK - windowName:nil - opener:parent - openedByDOM:NO - atIndex:1 - inBackground:NO]; - EXPECT_EQ([tabModel_ indexOfTab:parent], 3U); - EXPECT_EQ([tabModel_ indexOfTab:child1], 2U); - EXPECT_EQ([tabModel_ indexOfTab:child3], 1U); - EXPECT_EQ([tabModel_ indexOfTab:child2], 0U); + Tab* child3 = [tab_model_ insertOrUpdateTabWithURL:kURL + referrer:kEmptyReferrer + transition:ui::PAGE_TRANSITION_LINK + windowName:nil + opener:parent + openedByDOM:NO + atIndex:1 + inBackground:NO]; + EXPECT_EQ([tab_model_ indexOfTab:parent], 3U); + EXPECT_EQ([tab_model_ indexOfTab:child1], 2U); + EXPECT_EQ([tab_model_ indexOfTab:child3], 1U); + EXPECT_EQ([tab_model_ indexOfTab:child2], 0U); } TEST_F(TabModelTest, MoveTabs) { - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; - [tabModel_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; + [tab_model_ addTabWithURL:kURL referrer:kReferrer windowName:@"window 3"]; // Basic sanity checks before moving on. - ASSERT_EQ(3U, [tabModel_ count]); - ASSERT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:0] windowName]); - ASSERT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:1] windowName]); - ASSERT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:2] windowName]); + ASSERT_EQ(3U, [tab_model_ count]); + ASSERT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:0] windowName]); + ASSERT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:1] windowName]); + ASSERT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:2] windowName]); // Move a tab from index 1 to index 0 (move tab left by one). - [tabModelObserver_ setTabMovedWasCalled:NO]; - [tabModel_ moveTab:[tabModel_ tabAtIndex:1] toIndex:0]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_TRUE([tabModelObserver_ tabMovedWasCalled]); + [tab_model_observer_ setTabMovedWasCalled:NO]; + [tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:0]; + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_TRUE([tab_model_observer_ tabMovedWasCalled]); // Move a tab from index 1 to index 2 (move tab right by one). - [tabModelObserver_ setTabMovedWasCalled:NO]; - [tabModel_ moveTab:[tabModel_ tabAtIndex:1] toIndex:2]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_TRUE([tabModelObserver_ tabMovedWasCalled]); + [tab_model_observer_ setTabMovedWasCalled:NO]; + [tab_model_ moveTab:[tab_model_ tabAtIndex:1] toIndex:2]; + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_TRUE([tab_model_observer_ tabMovedWasCalled]); // Move a tab from index 0 to index 2 (move tab right by more than one). - [tabModelObserver_ setTabMovedWasCalled:NO]; - [tabModel_ moveTab:[tabModel_ tabAtIndex:0] toIndex:2]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_TRUE([tabModelObserver_ tabMovedWasCalled]); + [tab_model_observer_ setTabMovedWasCalled:NO]; + [tab_model_ moveTab:[tab_model_ tabAtIndex:0] toIndex:2]; + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_TRUE([tab_model_observer_ tabMovedWasCalled]); // Move a tab from index 2 to index 0 (move tab left by more than one). - [tabModelObserver_ setTabMovedWasCalled:NO]; - [tabModel_ moveTab:[tabModel_ tabAtIndex:2] toIndex:0]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_TRUE([tabModelObserver_ tabMovedWasCalled]); + [tab_model_observer_ setTabMovedWasCalled:NO]; + [tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:0]; + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_TRUE([tab_model_observer_ tabMovedWasCalled]); // Move a tab from index 2 to index 2 (move tab to the same index). - [tabModelObserver_ setTabMovedWasCalled:NO]; - [tabModel_ moveTab:[tabModel_ tabAtIndex:2] toIndex:2]; - ASSERT_EQ(3U, [tabModel_ count]); - EXPECT_NSEQ(@"window 2", [[tabModel_ tabAtIndex:0] windowName]); - EXPECT_NSEQ(@"window 3", [[tabModel_ tabAtIndex:1] windowName]); - EXPECT_NSEQ(@"window 1", [[tabModel_ tabAtIndex:2] windowName]); - EXPECT_FALSE([tabModelObserver_ tabMovedWasCalled]); + [tab_model_observer_ setTabMovedWasCalled:NO]; + [tab_model_ moveTab:[tab_model_ tabAtIndex:2] toIndex:2]; + ASSERT_EQ(3U, [tab_model_ count]); + EXPECT_NSEQ(@"window 2", [[tab_model_ tabAtIndex:0] windowName]); + EXPECT_NSEQ(@"window 3", [[tab_model_ tabAtIndex:1] windowName]); + EXPECT_NSEQ(@"window 1", [[tab_model_ tabAtIndex:2] windowName]); + EXPECT_FALSE([tab_model_observer_ tabMovedWasCalled]); } TEST_F(TabModelTest, SetParentModel) { @@ -838,20 +829,23 @@ browserState:chrome_browser_state_.get() tabModel:nil]); EXPECT_TRUE([tab parentTabModel] == nil); - [tabModel_ insertTab:tab atIndex:0]; - [tab setParentTabModel:tabModel_.get()]; + [tab_model_ insertTab:tab atIndex:0]; + [tab setParentTabModel:tab_model_.get()]; EXPECT_FALSE([tab parentTabModel] == nil); - [tabModel_ closeTabAtIndex:0]; + [tab_model_ closeTabAtIndex:0]; } TEST_F(TabModelTest, PersistSelectionChange) { + TestChromeBrowserState::Builder test_cbs_builder; + auto chrome_browser_state = test_cbs_builder.Build(); + NSString* stashPath = - base::SysUTF8ToNSString(chrome_browser_state_->GetStatePath().value()); + base::SysUTF8ToNSString(chrome_browser_state->GetStatePath().value()); base::scoped_nsobject<TabModel> model([[TabModel alloc] - initWithSessionWindow:sessionWindow_.get() + initWithSessionWindow:session_window_.get() sessionService:[SessionServiceIOS sharedService] - browserState:chrome_browser_state_.get()]); + browserState:chrome_browser_state.get()]); [model addTabWithURL:kURL referrer:kReferrer windowName:@"window 1"]; [model addTabWithURL:kURL referrer:kReferrer windowName:@"window 2"]; @@ -869,7 +863,7 @@ base::RunLoop().RunUntilIdle(); SessionWindowIOS* sessionWindow = [[SessionServiceIOS sharedService] - loadWindowForBrowserState:chrome_browser_state_.get()]; + loadWindowForBrowserState:chrome_browser_state.get()]; // Create tab model from saved session. base::scoped_nsobject<TestSessionService> test_service( @@ -878,7 +872,7 @@ model.reset([[TabModel alloc] initWithSessionWindow:sessionWindow sessionService:test_service - browserState:chrome_browser_state_.get()]); + browserState:chrome_browser_state.get()]); EXPECT_EQ(model.get().currentTab, [model tabAtIndex:1]); [model browserStateDestroyed];
diff --git a/ios/chrome/browser/tabs/tab_unittest.mm b/ios/chrome/browser/tabs/tab_unittest.mm index 9ae72de..0b10e80 100644 --- a/ios/chrome/browser/tabs/tab_unittest.mm +++ b/ios/chrome/browser/tabs/tab_unittest.mm
@@ -7,6 +7,7 @@ #include <memory> #include "base/callback.h" +#include "base/files/file_path.h" #include "base/ios/block_types.h" #include "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" @@ -19,6 +20,7 @@ #include "components/keyed_service/core/service_access_type.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h" #import "ios/chrome/browser/chrome_url_util.h" #include "ios/chrome/browser/history/history_service_factory.h" #import "ios/chrome/browser/tabs/tab.h" @@ -29,6 +31,7 @@ #import "ios/chrome/browser/web/external_app_launcher.h" #include "ios/chrome/test/block_cleanup_test.h" #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h" +#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h" #include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" #import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_metadata.h" #import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_whitelist_manager.h" @@ -160,7 +163,11 @@ class TabTest : public BlockCleanupTest { public: - TabTest() : thread_bundle_(web::TestWebThreadBundle::REAL_FILE_THREAD) {} + TabTest() + : thread_bundle_(web::TestWebThreadBundle::REAL_FILE_THREAD), + scoped_browser_state_manager_( + base::MakeUnique<TestChromeBrowserStateManager>(base::FilePath())) { + } void SetUp() override { BlockCleanupTest::SetUp(); @@ -310,7 +317,7 @@ protected: web::TestWebThreadBundle thread_bundle_; - IOSChromeScopedTestingLocalState local_state_; + IOSChromeScopedTestingChromeBrowserStateManager scoped_browser_state_manager_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; base::scoped_nsobject<Tab> tab_; history::HistoryService* history_service_; // weak @@ -549,10 +556,4 @@ EXPECT_FALSE([metadata shouldAutoOpenLinks]); } -class TestRequestGroupID : public BlockCleanupTest { - public: - void SetUp() override { BlockCleanupTest::SetUp(); } - void TearDown() override { BlockCleanupTest::TearDown(); } -}; - } // namespace
diff --git a/ios/chrome/browser/test/perf_test_with_bvc_ios.h b/ios/chrome/browser/test/perf_test_with_bvc_ios.h index 6ddb4a1..492f337 100644 --- a/ios/chrome/browser/test/perf_test_with_bvc_ios.h +++ b/ios/chrome/browser/test/perf_test_with_bvc_ios.h
@@ -13,7 +13,7 @@ #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/test/base/perf_test_ios.h" #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h" -#include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h" #include "ios/web/public/test/scoped_testing_web_client.h" @class BrowserViewController; @@ -47,7 +47,7 @@ web::ScopedTestingWebClient web_client_; IOSChromeScopedTestingChromeBrowserProvider provider_; - IOSChromeScopedTestingLocalState local_state_; + IOSChromeScopedTestingChromeBrowserStateManager browser_state_manager_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; std::unique_ptr<TestChromeBrowserState> incognito_chrome_browser_state_;
diff --git a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm index d0886cf6..546efc3 100644 --- a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm +++ b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
@@ -6,11 +6,13 @@ #import <UIKit/UIKit.h> +#include "base/files/file_path.h" #include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" #include "components/bookmarks/test/bookmark_test_helpers.h" #include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h" #include "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/session_service.h" #import "ios/chrome/browser/sessions/session_window.h" @@ -66,7 +68,9 @@ : PerfTest(testGroup), slow_teardown_(false), web_client_(base::MakeUnique<ChromeWebClient>()), - provider_(ios::CreateChromeBrowserProvider()) {} + provider_(ios::CreateChromeBrowserProvider()), + browser_state_manager_( + base::MakeUnique<TestChromeBrowserStateManager>(base::FilePath())) {} PerfTestWithBVC::PerfTestWithBVC(std::string testGroup, std::string firstLabel, @@ -83,7 +87,9 @@ repeat), slow_teardown_(slowTeardown), web_client_(base::MakeUnique<ChromeWebClient>()), - provider_(ios::CreateChromeBrowserProvider()) {} + provider_(ios::CreateChromeBrowserProvider()), + browser_state_manager_( + base::MakeUnique<TestChromeBrowserStateManager>(base::FilePath())) {} PerfTestWithBVC::~PerfTestWithBVC() {}
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn index a786891..686ad438 100644 --- a/ios/chrome/browser/ui/BUILD.gn +++ b/ios/chrome/browser/ui/BUILD.gn
@@ -233,7 +233,6 @@ "prerender_delegate.h", ] deps = [ - ":browser_list", ":resources", ":ui", "//base", @@ -343,18 +342,6 @@ ] } -source_set("browser_list") { - sources = [ - "browser_ios.h", - "browser_list_ios.h", - "browser_list_ios.mm", - ] - deps = [ - "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/tabs", - ] -} - source_set("test_support") { testonly = true sources = [
diff --git a/ios/chrome/browser/ui/browser_ios.h b/ios/chrome/browser/ui/browser_ios.h deleted file mode 100644 index a65005a..0000000 --- a/ios/chrome/browser/ui/browser_ios.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_BROWSER_IOS_H_ -#define IOS_CHROME_BROWSER_UI_BROWSER_IOS_H_ - -#import <Foundation/Foundation.h> - -namespace ios { -class ChromeBrowserState; -} - -@class TabModel; - -// Modeled after chrome/browser/ui/browser, just an abstract interface to -// a browser to get the browser state and tabs from but can go into a -// BrowserListIOS. -@protocol BrowserIOS - -- (ios::ChromeBrowserState*)browserState; -- (TabModel*)tabModel; - -@end - -#endif // IOS_CHROME_BROWSER_UI_BROWSER_IOS_H_
diff --git a/ios/chrome/browser/ui/browser_list_ios.h b/ios/chrome/browser/ui/browser_list_ios.h deleted file mode 100644 index a08d490..0000000 --- a/ios/chrome/browser/ui/browser_list_ios.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_BROWSER_LIST_IOS_H_ -#define IOS_CHROME_BROWSER_UI_BROWSER_LIST_IOS_H_ - -#include <vector> - -#import "ios/chrome/browser/ui/browser_ios.h" - -namespace ios { -class ChromeBrowserState; -} - -// Modeled after chrome/browser/ui/browser_list. - -class BrowserListIOS { - public: - typedef std::vector<id<BrowserIOS>> BrowserVector; - typedef BrowserVector::iterator iterator; - typedef BrowserVector::const_iterator const_iterator; - - // Note: browsers are not retained, just like desktop browser lists, their - // management is outside the list. - static void AddBrowser(id<BrowserIOS> browser); - static void RemoveBrowser(id<BrowserIOS> browser); - - static id<BrowserIOS> GetLastActiveWithBrowserState( - ios::ChromeBrowserState* browser_state); - - static const_iterator begin(); - static const_iterator end(); - - static bool empty() { return !browsers_ || browsers_->empty(); } - static size_t size() { return browsers_ ? browsers_->size() : 0; } - - // Returns true if at least one incognito session is active. - static bool IsOffTheRecordSessionActive(); - - private: - static BrowserVector* browsers_; - - static void EnsureBrowsersIsValid(); -}; - -#endif // IOS_CHROME_BROWSER_UI_BROWSER_LIST_IOS_H_
diff --git a/ios/chrome/browser/ui/browser_list_ios.mm b/ios/chrome/browser/ui/browser_list_ios.mm deleted file mode 100644 index 3e09bcf..0000000 --- a/ios/chrome/browser/ui/browser_list_ios.mm +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/browser_list_ios.h" - -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/tabs/tab_model.h" - -BrowserListIOS::BrowserVector* BrowserListIOS::browsers_; - -void BrowserListIOS::AddBrowser(id<BrowserIOS> browser) { - EnsureBrowsersIsValid(); - DCHECK(browser); - browsers_->push_back(browser); -} - -void BrowserListIOS::RemoveBrowser(id<BrowserIOS> browser) { - if (!browsers_) - return; - DCHECK(browser); - const iterator remove_browser = - std::find(browsers_->begin(), browsers_->end(), browser); - if (remove_browser != browsers_->end()) - browsers_->erase(remove_browser); -} - -id<BrowserIOS> BrowserListIOS::GetLastActiveWithBrowserState( - ios::ChromeBrowserState* browser_state) { - DCHECK(browser_state); - for (const_iterator i = BrowserListIOS::begin(); i != BrowserListIOS::end(); - ++i) { - if ([*i browserState] == browser_state) - return *i; - } - return NULL; -} - -BrowserListIOS::const_iterator BrowserListIOS::begin() { - EnsureBrowsersIsValid(); - return browsers_->begin(); -} - -BrowserListIOS::const_iterator BrowserListIOS::end() { - EnsureBrowsersIsValid(); - return browsers_->end(); -} - -// static -bool BrowserListIOS::IsOffTheRecordSessionActive() { - for (const_iterator i = BrowserListIOS::begin(); i != BrowserListIOS::end(); - ++i) { - // Unlike desktop, an Incognito browser can exist but be empty, so filter - // that case out. - if ([*i browserState] && [*i browserState]->IsOffTheRecord() && - ![[*i tabModel] isEmpty]) - return true; - } - return false; -} - -void BrowserListIOS::EnsureBrowsersIsValid() { - if (browsers_) - return; - browsers_ = new BrowserVector; -}
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h index 6531d86..c532693 100644 --- a/ios/chrome/browser/ui/browser_view_controller.h +++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -10,7 +10,6 @@ #import <UIKit/UIKit.h> #import "base/ios/block_types.h" -#import "ios/chrome/browser/ui/browser_ios.h" #import "ios/chrome/browser/ui/side_swipe/side_swipe_controller.h" #import "ios/chrome/browser/ui/toolbar/toolbar_owner.h" #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h" @@ -51,8 +50,7 @@ // The top-level view controller for the browser UI. Manages other controllers // which implement the interface. -@interface BrowserViewController : UIViewController<BrowserIOS, - SideSwipeControllerDelegate, +@interface BrowserViewController : UIViewController<SideSwipeControllerDelegate, ToolbarOwner, UrlLoader, VoiceSearchPresenter, @@ -93,6 +91,12 @@ // Returns whether or not text to speech is playing. @property(nonatomic, assign, readonly, getter=isPlayingTTS) BOOL playingTTS; +// Returns the TabModel passed to the initializer. +@property(nonatomic, assign, readonly) TabModel* tabModel; + +// Returns the ios::ChromeBrowserState passed to the initializer. +@property(nonatomic, assign, readonly) ios::ChromeBrowserState* browserState; + // Whether the receiver is currently the primary BVC. - (void)setPrimary:(BOOL)primary;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index c3fda741..b768c1e4 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -88,7 +88,6 @@ #import "ios/chrome/browser/ui/background_generator.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" #import "ios/chrome/browser/ui/browser_container_view.h" -#import "ios/chrome/browser/ui/browser_list_ios.h" #import "ios/chrome/browser/ui/browser_view_controller_dependency_factory.h" #import "ios/chrome/browser/ui/chrome_web_view_factory.h" #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" @@ -917,7 +916,6 @@ // TODO(leng): Delay this. [[UpgradeCenter sharedInstance] registerClient:self]; _inNewTabAnimation = NO; - BrowserListIOS::AddBrowser(self); if (model && browserState) [self updateWithTabModel:model browserState:browserState]; if ([[NSUserDefaults standardUserDefaults] @@ -943,7 +941,6 @@ _tabStripController.reset(); _infoBarContainer.reset(); _readingListMenuNotifier.reset(); - BrowserListIOS::RemoveBrowser(self); _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get()); [_model removeObserver:self]; [[UpgradeCenter sharedInstance] unregisterClient:self]; @@ -1044,6 +1041,14 @@ return _voiceSearchController && _voiceSearchController->IsPlayingAudio(); } +- (ios::ChromeBrowserState*)browserState { + return _browserState; +} + +- (TabModel*)tabModel { + return _model.get(); +} + - (SideSwipeController*)sideSwipeController { if (!_sideSwipeController) { _sideSwipeController.reset([[SideSwipeController alloc] @@ -1672,7 +1677,6 @@ [_contextualSearchMask removeFromSuperview]; [_paymentRequestManager close]; _paymentRequestManager.reset(); - BrowserListIOS::RemoveBrowser(self); [_toolbarController browserStateDestroyed]; [_model browserStateDestroyed]; [_preloadController browserStateDestroyed]; @@ -3239,16 +3243,6 @@ } } -#pragma mark - BrowserIOS methods - -- (ios::ChromeBrowserState*)browserState { - return _browserState; -} - -- (TabModel*)tabModel { - return _model.get(); -} - #pragma mark - No-tabs UI methods // Show the No-Tabs UI (hiding normal tab/web ui). @@ -3503,7 +3497,8 @@ ReadingListModel* readingModel = ReadingListModelFactory::GetForBrowserState(_browserState); - readingModel->AddEntry(URL, base::SysNSStringToUTF8(title)); + readingModel->AddEntry(URL, base::SysNSStringToUTF8(title), + reading_list::ADDED_VIA_CURRENT_APP); NSString* snackBarMessage = l10n_util::GetNSString(IDS_IOS_READING_LIST_SNACKBAR_MESSAGE);
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm index d1dee07..53f7535f 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -142,12 +142,16 @@ // enter edit mode. void AddEntriesAndEnterEdit() { ReadingListModel* model = GetReadingListModel(); - model->AddEntry(GURL(kReadURL), std::string(kReadTitle)); + model->AddEntry(GURL(kReadURL), std::string(kReadTitle), + reading_list::ADDED_VIA_CURRENT_APP); model->SetReadStatus(GURL(kReadURL), true); - model->AddEntry(GURL(kReadURL2), std::string(kReadTitle2)); + model->AddEntry(GURL(kReadURL2), std::string(kReadTitle2), + reading_list::ADDED_VIA_CURRENT_APP); model->SetReadStatus(GURL(kReadURL2), true); - model->AddEntry(GURL(kUnreadURL), std::string(kUnreadTitle)); - model->AddEntry(GURL(kUnreadURL2), std::string(kUnreadTitle2)); + model->AddEntry(GURL(kUnreadURL), std::string(kUnreadTitle), + reading_list::ADDED_VIA_CURRENT_APP); + model->AddEntry(GURL(kUnreadURL2), std::string(kUnreadTitle2), + reading_list::ADDED_VIA_CURRENT_APP); OpenReadingList(); TapButtonWithID(IDS_IOS_READING_LIST_EDIT_BUTTON); @@ -237,7 +241,8 @@ // Tests that only the "Edit" button is showing when not editing. - (void)testVisibleButtonsNonEditingMode { - GetReadingListModel()->AddEntry(GURL(kUnreadURL), std::string(kUnreadTitle)); + GetReadingListModel()->AddEntry(GURL(kUnreadURL), std::string(kUnreadTitle), + reading_list::ADDED_VIA_CURRENT_APP); OpenReadingList(); AssertButtonNotVisibleWithID(IDS_IOS_READING_LIST_DELETE_BUTTON);
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm index 8ea20799..be6f720a 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm
@@ -113,9 +113,12 @@ // Tests that reading list items are displayed. TEST_F(ReadingListViewControllerTest, DisplaysItems) { // Prefill some items. - reading_list_model_->AddEntry(GURL("https://chromium.org"), "news"); - reading_list_model_->AddEntry(GURL("https://mail.chromium.org"), "mail"); - reading_list_model_->AddEntry(GURL("https://foo.bar"), "Foo"); + reading_list_model_->AddEntry(GURL("https://chromium.org"), "news", + reading_list::ADDED_VIA_CURRENT_APP); + reading_list_model_->AddEntry(GURL("https://mail.chromium.org"), "mail", + reading_list::ADDED_VIA_CURRENT_APP); + reading_list_model_->AddEntry(GURL("https://foo.bar"), "Foo", + reading_list::ADDED_VIA_CURRENT_APP); reading_list_model_->SetReadStatus(GURL("https://foo.bar"), true); // Load view. @@ -157,7 +160,8 @@ [OCMockObject partialMockForObject:reading_list_view_controller_.get()]; GURL url("https://chromium.org"); - reading_list_model_->AddEntry(url, "chromium"); + reading_list_model_->AddEntry(url, "chromium", + reading_list::ADDED_VIA_CURRENT_APP); [reading_list_view_controller_ view]; [[partialMock expect] dismiss];
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn index c62a0c89..b2a94729 100644 --- a/ios/chrome/browser/ui/toolbar/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -31,9 +31,6 @@ "resources/toolbar_dark_newtab_incognito_active.png", "resources/toolbar_dark_newtab_incognito_active@2x.png", "resources/toolbar_dark_newtab_incognito_active@3x.png", - "resources/toolbar_tools.png", - "resources/toolbar_tools@2x.png", - "resources/toolbar_tools@3x.png", ] outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}", @@ -167,12 +164,10 @@ "//ios/chrome/browser", "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state:test_support", - "//ios/chrome/browser/ssl", "//ios/chrome/browser/tabs", "//ios/chrome/browser/ui", "//ios/chrome/test:test_support", "//ios/testing:ocmock_support", - "//ios/web", "//ios/web:test_support", "//testing/gtest", "//third_party/ocmock",
diff --git a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools.png b/ios/chrome/browser/ui/toolbar/resources/toolbar_tools.png deleted file mode 100644 index ff90580..0000000 --- a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools.png +++ /dev/null Binary files differ
diff --git a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@2x.png b/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@2x.png deleted file mode 100644 index 71ba4df..0000000 --- a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@2x.png +++ /dev/null Binary files differ
diff --git a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@3x.png b/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@3x.png deleted file mode 100644 index 9d00d1e..0000000 --- a/ios/chrome/browser/ui/toolbar/resources/toolbar_tools@3x.png +++ /dev/null Binary files differ
diff --git a/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.h b/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.h index 5e63a41..18153d4 100644 --- a/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.h +++ b/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.h
@@ -18,10 +18,8 @@ TestToolbarModelIOS(); ~TestToolbarModelIOS() override; - // Getter to the TestToolbarModel to set its values in tests. - TestToolbarModel* GetToolbarModel(); - // ToolbarModelIOS implementation: + ToolbarModel* GetToolbarModel() override; bool IsLoading() override; CGFloat GetLoadProgressFraction() override; bool CanGoBack() override; @@ -31,15 +29,6 @@ bool IsCurrentTabBookmarkedByUser() override; bool ShouldDisplayHintText() override; - base::string16 GetFormattedURL(size_t* prefix_end) const override; - GURL GetURL() const override; - security_state::SecurityLevel GetSecurityLevel( - bool ignore_editing) const override; - gfx::VectorIconId GetVectorIcon() const override; - base::string16 GetSecureVerboseText() const override; - base::string16 GetEVCertName() const override; - bool ShouldDisplayURL() const override; - void set_is_loading(bool is_loading) { is_loading_ = is_loading; } void set_load_progress_fraction(CGFloat load_progress_fraction) { load_progress_fraction_ = load_progress_fraction;
diff --git a/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.mm b/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.mm index 6511803..11736d3 100644 --- a/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.mm +++ b/ios/chrome/browser/ui/toolbar/test_toolbar_model_ios.mm
@@ -20,7 +20,7 @@ TestToolbarModelIOS::~TestToolbarModelIOS() {} -TestToolbarModel* TestToolbarModelIOS::GetToolbarModel() { +ToolbarModel* TestToolbarModelIOS::GetToolbarModel() { return test_toolbar_model_.get(); } @@ -56,31 +56,3 @@ return false; } -base::string16 TestToolbarModelIOS::GetFormattedURL(size_t* prefix_end) const { - return test_toolbar_model_->GetFormattedURL(prefix_end); -} - -GURL TestToolbarModelIOS::GetURL() const { - return test_toolbar_model_->GetURL(); -} - -security_state::SecurityLevel TestToolbarModelIOS::GetSecurityLevel( - bool ignore_editing) const { - return test_toolbar_model_->GetSecurityLevel(ignore_editing); -} - -gfx::VectorIconId TestToolbarModelIOS::GetVectorIcon() const { - return test_toolbar_model_->GetVectorIcon(); -} - -base::string16 TestToolbarModelIOS::GetSecureVerboseText() const { - return test_toolbar_model_->GetSecureVerboseText(); -} - -base::string16 TestToolbarModelIOS::GetEVCertName() const { - return test_toolbar_model_->GetEVCertName(); -} - -bool TestToolbarModelIOS::ShouldDisplayURL() const { - return test_toolbar_model_->ShouldDisplayURL(); -}
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h index c146fc09..6b53dac 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h +++ b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h
@@ -18,6 +18,7 @@ ~ToolbarModelImplIOS() override; // ToolbarModelIOS implementation: + ToolbarModel* GetToolbarModel() override; bool IsLoading() override; CGFloat GetLoadProgressFraction() override; bool CanGoBack() override; @@ -28,17 +29,6 @@ bool ShouldDisplayHintText() override; private: - // ToolbarModel: - base::string16 GetFormattedURL(size_t* prefix_end) const override; - GURL GetURL() const override; - security_state::SecurityLevel GetSecurityLevel( - bool ignore_editing) const override; - gfx::VectorIconId GetVectorIcon() const override; - base::string16 GetSecureVerboseText() const override; - base::string16 GetEVCertName() const override; - bool ShouldDisplayURL() const override; - - private: ToolbarModelDelegateIOS* delegate_; std::unique_ptr<ToolbarModel> toolbar_model_;
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.mm b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.mm index e8db613..ee723d97 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.mm
@@ -9,10 +9,8 @@ #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" -#include "ios/chrome/browser/reading_list/offline_url_utils.h" #import "ios/chrome/browser/tabs/tab.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h" -#import "ios/web/public/navigation_item.h" #import "ios/web/public/web_state/web_state.h" namespace { @@ -37,6 +35,10 @@ ToolbarModelImplIOS::~ToolbarModelImplIOS() {} +ToolbarModel* ToolbarModelImplIOS::GetToolbarModel() { + return toolbar_model_.get(); +} + bool ToolbarModelImplIOS::IsLoading() { // Please note, ToolbarModel's notion of isLoading is slightly different from // WebState's IsLoading(). @@ -81,50 +83,3 @@ return [current_tab.webController wantsLocationBarHintText]; } -base::string16 ToolbarModelImplIOS::GetFormattedURL(size_t* prefix_end) const { - base::string16 formatted_url = toolbar_model_->GetFormattedURL(prefix_end); - Tab* current_tab = delegate_->GetCurrentTab(); - if (!current_tab || !current_tab.webState || - !current_tab.webState->GetNavigationManager() || - !current_tab.webState->GetNavigationManager()->GetVisibleItem()) { - return formatted_url; - } - GURL url = - current_tab.webState->GetNavigationManager()->GetVisibleItem()->GetURL(); - if (reading_list::IsOfflineURL(url) && - GetSecurityLevel(true /*ignore_editing*/) == - security_state::SecurityLevel::NONE) { - size_t removed = 0; - formatted_url = - reading_list::StripSchemeFromOnlineURL(formatted_url, &removed); - if (prefix_end) { - *prefix_end -= removed; - } - } - return formatted_url; -} - -GURL ToolbarModelImplIOS::GetURL() const { - return toolbar_model_->GetURL(); -} - -security_state::SecurityLevel ToolbarModelImplIOS::GetSecurityLevel( - bool ignore_editing) const { - return toolbar_model_->GetSecurityLevel(ignore_editing); -} - -gfx::VectorIconId ToolbarModelImplIOS::GetVectorIcon() const { - return toolbar_model_->GetVectorIcon(); -} - -base::string16 ToolbarModelImplIOS::GetSecureVerboseText() const { - return toolbar_model_->GetSecureVerboseText(); -} - -base::string16 ToolbarModelImplIOS::GetEVCertName() const { - return toolbar_model_->GetEVCertName(); -} - -bool ToolbarModelImplIOS::ShouldDisplayURL() const { - return toolbar_model_->ShouldDisplayURL(); -}
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios_unittest.mm b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios_unittest.mm index 958bf3f..308a1b0 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios_unittest.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios_unittest.mm
@@ -7,7 +7,6 @@ #include <memory> #include "base/mac/scoped_nsobject.h" -#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "components/bookmarks/browser/bookmark_model.h" @@ -15,15 +14,12 @@ #include "components/toolbar/test_toolbar_model.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h" #import "ios/chrome/browser/tabs/tab.h" #import "ios/chrome/browser/tabs/tab_model.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_impl_ios.h" #import "ios/chrome/browser/xcallback_parameters.h" #import "ios/testing/ocmock_complex_type_helper.h" -#import "ios/web/public/navigation_item.h" -#import "ios/web/public/test/fakes/test_navigation_manager.h" #import "ios/web/public/test/fakes/test_web_state.h" #include "ios/web/public/test/test_web_thread.h" #include "ios/web/public/test/test_web_thread_bundle.h" @@ -221,58 +217,4 @@ EXPECT_FALSE(toolbarModel_->IsCurrentTabBookmarked()); } -TEST_F(ToolbarModelImplIOSTest, TestGetFormattedURL) { - ToolbarModelImplIOSTestWebState web_state(chrome_browser_state_.get()); - IOSSecurityStateTabHelper::CreateForWebState(&web_state); - auto test_navigation_manager = base::MakeUnique<web::TestNavigationManager>(); - auto visible_item = web::NavigationItem::Create(); - test_navigation_manager->SetVisibleItem(visible_item.get()); - web_state.SetNavigationManager(std::move(test_navigation_manager)); - id tabMock = [[TMITestTabMock alloc] - initWithRepresentedObject:[OCMockObject mockForClass:[Tab class]]]; - OCMockObject* tabModelMock = static_cast<OCMockObject*>(tabModel_.get()); - [[[tabModelMock stub] andReturn:tabMock] currentTab]; - [static_cast<TMITestTabMock*>(tabMock) setWebState:&web_state]; - - size_t length = 0; - const char no_scheme_url[] = "www.chromium.org"; - const char http_url[] = "http://www.chromium.org"; - const char https_url[] = "https://www.chromium.org"; - const char chrome_url[] = "chrome://www.chromium.org"; - const char offline_url[] = "chrome://offline/testid/page.html"; - // Test that only http:// scheme is stripped out for online URL. - visible_item->SetURL(GURL(http_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(no_scheme_url)); - EXPECT_EQ(length, 0u); - - visible_item->SetURL(GURL(https_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(https_url)); - EXPECT_EQ(length, 8u); - - visible_item->SetURL(GURL(chrome_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(chrome_url)); - EXPECT_EQ(length, 9u); - - // Test that only http:// and https:// scheme are stripped out for offline - // URL. - visible_item->SetURL(GURL(offline_url)); - visible_item->SetVirtualURL(GURL(http_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(no_scheme_url)); - EXPECT_EQ(length, 0u); - - visible_item->SetVirtualURL(GURL(https_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(no_scheme_url)); - EXPECT_EQ(length, 0u); - - visible_item->SetVirtualURL(GURL(chrome_url)); - EXPECT_EQ(toolbarModel_->GetFormattedURL(&length), - base::UTF8ToUTF16(chrome_url)); - EXPECT_EQ(length, 9u); -} - } // namespace
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_model_ios.h b/ios/chrome/browser/ui/toolbar/toolbar_model_ios.h index b471271..9c98fbe 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_model_ios.h +++ b/ios/chrome/browser/ui/toolbar/toolbar_model_ios.h
@@ -9,8 +9,15 @@ #include "components/toolbar/toolbar_model.h" -class ToolbarModelIOS : public ToolbarModel { +// This class adds some IOS specific methods to the ToolbarModel. +// It does not inherit from ToolbarModel on purpose. +class ToolbarModelIOS { public: + virtual ~ToolbarModelIOS() {} + + // Returns the |ToolbarModel| contained by this instance. + virtual ToolbarModel* GetToolbarModel() = 0; + // Returns true if the current tab is currently loading. virtual bool IsLoading() = 0;
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h b/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h index 433719d..6a88fdb 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h +++ b/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h
@@ -13,6 +13,7 @@ // TintedButton specialization that updates the tint color when the tools menu // is visible or when the reading list associated with |readingListModel| // contains unread items. +// Draws and animates the icon of the button using UIBezierPaths. @interface ToolbarToolsMenuButton : TintedButton // Initializes and returns a newly allocated TintedButton with the specified @@ -32,6 +33,10 @@ // items. - (void)setReadingListContainsUnseenItems:(BOOL)readingListContainsUnseenItems; +// Triggers an animation on the button to draw the user's attention to the +// button. +- (void)triggerAnimation; + @end #endif // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_TOOLS_MENU_BUTTON_H_
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.mm b/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.mm index 29de8ed..dff031a 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.mm
@@ -4,23 +4,70 @@ #import "ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h" +#import <QuartzCore/CAAnimation.h> +#import <QuartzCore/CAMediaTimingFunction.h> + #include "ios/chrome/browser/ui/toolbar/toolbar_button_tints.h" -#import "ios/chrome/browser/ui/uikit_ui_util.h" -@interface ToolbarToolsMenuButton () -// Updates the tint configuration based on the button's situation, e.g. whether -// the tools menu is visible or not. -- (void)updateTintOfButton; -@end +namespace { +// The number of dots drawn. +const int kNumberOfDots = 3; +// Position of the topmost dot. +const CGFloat kDotOffsetX = 22; +const CGFloat kDotOffsetY = 18; +// Vertical space between dots. +const CGFloat kVerticalSpaceBetweenDots = 6; +// The duration of the animation, in seconds. +const CFTimeInterval kAnimationDuration = 1; +// The frame offset at which the animation to the intermediary value finishes. +const int kIntermediaryValueBeginFrame = 15; +// The frame offset at which the animation to the final value starts. +const int kIntermediaryValueEndFrame = 29; +// The frame offset at which the animation to the final value finishes. +const int kFinalValueBeginFrame = 37; +// The number of frames between the start of each dot's animation. +const double kFramesBetweenAnimationOfEachDot = 3; +// The maximum width of the segment/dots. +const CGFloat kMaxWidthOfSegment = 7.4; +// Constants for the properties of the stroke during the animations. +// The strokeEnd is slightly more than 0.5, because if the strokeEnd is +// exactly equal to strokeStart, the line is not drawn. +const CGFloat kStrokeStartAtRest = 0.5; +const CGFloat kStrokeEndAtRest = kStrokeStartAtRest + 0.001; +const CGFloat kLineWidthAtRest = 4; +const CGFloat kStrokeStartAtApogee = 0; +const CGFloat kStrokeEndAtApogee = 1; +const CGFloat kLineWidthAtApogee = 3; +} // namespace -@interface ToolbarToolsMenuButton () { +@interface ToolbarToolsMenuButton ()<CAAnimationDelegate> { // The style of the toolbar the button is in. ToolbarControllerStyle style_; // Whether the tools menu is visible. BOOL toolsMenuVisible_; // Whether the reading list contains unseen items. BOOL readingListContainsUnseenItems_; + // The CALayers containing the drawn dots. + base::scoped_nsobject<CAShapeLayer> pathLayers_[kNumberOfDots]; + // Whether the CALayers are being animated. + BOOL animationOnGoing_; } +// Updates the tint configuration based on the button's situation, e.g. whether +// the tools menu is visible or not. +- (void)updateTintOfButton; +// Initializes the pathLayers. +- (void)initializeShapeLayers; +// Returns a keyframe-based animation of the property identified by |keyPath|. +// The animation immidiately sets the property's value to |initialValue|. +// After |frameStart| frames, the property's value animates to +// |intermediaryValue|, and then to |finalValue|. +- (CAAnimation*)animationWithInitialValue:(id)initialValue + intermediaryValue:(id)intermediaryValue + finalValue:(id)finalValue + frameStart:(int)frameStart + forKeyPath:(NSString*)keyPath; +// Starts animating the button towards the color |targetColor|. +- (void)animateToColor:(UIColor*)targetColor; @end @implementation ToolbarToolsMenuButton @@ -34,11 +81,6 @@ forState:UIControlStateNormal]; [self setTintColor:toolbar::HighlighButtonTint(style_) forState:UIControlStateHighlighted]; - - [self setImageEdgeInsets:UIEdgeInsetsMakeDirected(0, -3, 0, 0)]; - UIImage* image = [UIImage imageNamed:@"toolbar_tools"]; - image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - [self setImage:image forState:UIControlStateNormal]; } return self; } @@ -53,6 +95,10 @@ [self updateTintOfButton]; } +- (void)triggerAnimation { + [self animateToColor:toolbar::HighlighButtonTint(style_)]; +} + #pragma mark - Private - (void)updateTintOfButton { @@ -65,4 +111,179 @@ } } +- (void)initializeShapeLayers { + for (int i = 0; i < kNumberOfDots; i++) { + base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; + if (pathLayer) { + [pathLayer removeFromSuperlayer]; + } + + const CGFloat x = kDotOffsetX; + const CGFloat y = kDotOffsetY + kVerticalSpaceBetweenDots * i; + + UIBezierPath* path = [UIBezierPath bezierPath]; + [path moveToPoint:CGPointMake(x - kMaxWidthOfSegment * 0.5, y)]; + [path addLineToPoint:CGPointMake(x + kMaxWidthOfSegment * 0.5, y)]; + + pathLayer.reset([[CAShapeLayer layer] retain]); + [pathLayer setFrame:self.bounds]; + [pathLayer setPath:path.CGPath]; + [pathLayer setStrokeColor:[self.tintColor CGColor]]; + [pathLayer setFillColor:nil]; + [pathLayer setLineWidth:kLineWidthAtRest]; + [pathLayer setLineCap:kCALineCapRound]; + [pathLayer setStrokeStart:kStrokeStartAtRest]; + [pathLayer setStrokeEnd:kStrokeEndAtRest]; + [self.layer addSublayer:pathLayer.get()]; + } +} + +- (CAAnimation*)animationWithInitialValue:(id)initialValue + intermediaryValue:(id)intermediaryValue + finalValue:(id)finalValue + frameStart:(int)frameStart + forKeyPath:(NSString*)keyPath { + // The property is animated the following way: + // + // value + // ^ + // | .final...final + // | . + // | .intermediary...intermediary. + // | . + // initial...initial. + // | + // +---------+-----------+--------------+-----------+-------+---> frames + // 0 start | | | 60 + // start+ | start+ + // kIntermediaryValueBeginFrame | kFinalValueBeginFrame + // | + // start+ + // kIntermediaryValueEndFrame + + CAKeyframeAnimation* animation = + [CAKeyframeAnimation animationWithKeyPath:keyPath]; + animation.duration = kAnimationDuration; + animation.removedOnCompletion = NO; + + // Set up the values. + animation.values = @[ + initialValue, initialValue, intermediaryValue, intermediaryValue, + finalValue, finalValue + ]; + + // Set up the timing functions. + NSMutableArray* timings = [NSMutableArray array]; + for (size_t i = 0; i < [animation.values count] - 1; i++) + [timings addObject:[CAMediaTimingFunction + functionWithName:kCAMediaTimingFunctionEaseIn]]; + animation.timingFunctions = timings; + + // Set up the key times. + const double totalNumberOfFrames = 60 * kAnimationDuration; + animation.keyTimes = @[ + @0, @(frameStart / totalNumberOfFrames), + @((frameStart + kIntermediaryValueBeginFrame) / totalNumberOfFrames), + @((frameStart + kIntermediaryValueEndFrame) / totalNumberOfFrames), + @((frameStart + kFinalValueBeginFrame) / totalNumberOfFrames), @1 + ]; + + DCHECK_EQ([animation.keyTimes count], [animation.values count]); + DCHECK_EQ([animation.keyTimes count] - 1, [animation.timingFunctions count]); + +#if DCHECK_IS_ON() + for (NSNumber* number in animation.keyTimes) { + DCHECK_GE([number floatValue], 0); + DCHECK_LE([number floatValue], 1); + } +#endif + + return animation; +} + +- (void)animateToColor:(UIColor*)targetColor { + animationOnGoing_ = YES; + + // Add four animations for each stroke. + for (int i = 0; i < kNumberOfDots; i++) { + base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; + DCHECK(pathLayer.get()); + const int frameStart = + (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; + + // Start of the stroke animation. + CAAnimation* strokeStartAnimation = + [self animationWithInitialValue:@(kStrokeStartAtRest) + intermediaryValue:@(kStrokeStartAtApogee) + finalValue:@(kStrokeStartAtRest) + frameStart:frameStart + forKeyPath:@"strokeStart"]; + + // End of the stroke animation. + CAAnimation* strokeEndAnimation = + [self animationWithInitialValue:@(kStrokeEndAtRest) + intermediaryValue:@(kStrokeEndAtApogee) + finalValue:@(kStrokeEndAtRest) + frameStart:frameStart + forKeyPath:@"strokeEnd"]; + + // Width of the stroke animation. + CAAnimation* lineWidthAnimation = + [self animationWithInitialValue:@(kLineWidthAtRest) + intermediaryValue:@(kLineWidthAtApogee) + finalValue:@(kLineWidthAtRest) + frameStart:frameStart + forKeyPath:@"lineWidth"]; + + // Color of the stroke animation. + CGColorRef initialColor = self.tintColor.CGColor; + CGColorRef finalColor = targetColor.CGColor; + CAAnimation* colorAnimation = + [self animationWithInitialValue:(__bridge id)initialColor + intermediaryValue:(__bridge id)finalColor + finalValue:(__bridge id)finalColor + frameStart:frameStart + forKeyPath:@"strokeColor"]; + colorAnimation.fillMode = kCAFillModeForwards; + + // |self| needs to know when the animations are finished. This is achieved + // by having |self| be registered as a CAAnimationDelegate. + // Because all animations have the same duration, any animation can be used. + // Arbitrarly use the |strokeStartAnimation| of the first dot. + if (i == 0) { + strokeStartAnimation.delegate = self; + } + + [pathLayer addAnimation:strokeStartAnimation forKey:nil]; + [pathLayer addAnimation:strokeEndAnimation forKey:nil]; + [pathLayer addAnimation:lineWidthAnimation forKey:nil]; + [pathLayer addAnimation:colorAnimation forKey:nil]; + } + + self.tintColor = targetColor; +} + +#pragma mark - UIView + +- (void)tintColorDidChange { + // The CAShapeLayer needs to be recreated when the tint color changes, to + // reflect the tint color. + // However, recreating the CAShapeLayer while it is animating cancels the + // animation. To avoid canceling the animation, skip recreating the + // CAShapeLayer when an animation is on going. + // To reflect any potential tint color change, the CAShapeLayer will be + // recreated at the end of the animation. + if (!animationOnGoing_) + [self initializeShapeLayers]; +} + +#pragma mark - CAAnimationDelegate + +- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { + animationOnGoing_ = NO; + // Recreate the CAShapeLayers in case the tint code changed while the + // animation was going on. + [self initializeShapeLayers]; +} + @end
diff --git a/ios/chrome/browser/ui/toolbar/tools_menu_button_observer_bridge.mm b/ios/chrome/browser/ui/toolbar/tools_menu_button_observer_bridge.mm index aed29ae..965fbd75 100644 --- a/ios/chrome/browser/ui/toolbar/tools_menu_button_observer_bridge.mm +++ b/ios/chrome/browser/ui/toolbar/tools_menu_button_observer_bridge.mm
@@ -34,6 +34,21 @@ return self; } +- (void)updateButtonWithModel:(const ReadingListModel*)model { + DCHECK(model == _model); + BOOL readingListContainsUnseenItems = model->GetLocalUnseenFlag(); + [_button setReadingListContainsUnseenItems:readingListContainsUnseenItems]; +} + +- (void)buttonPressed:(UIButton*)sender { + if (_model) { + _model->ResetLocalUnseenFlag(); + } + [_button setReadingListContainsUnseenItems:NO]; +} + +#pragma mark - ReadingListModelBridgeObserver + - (void)readingListModelLoaded:(const ReadingListModel*)model { [self updateButtonWithModel:model]; } @@ -47,17 +62,11 @@ _model = nullptr; } -- (void)updateButtonWithModel:(const ReadingListModel*)model { - DCHECK(model == _model); - BOOL readingListContainsUnseenItems = model->GetLocalUnseenFlag(); - [_button setReadingListContainsUnseenItems:readingListContainsUnseenItems]; -} - -- (void)buttonPressed:(UIButton*)sender { - if (_model) { - _model->ResetLocalUnseenFlag(); - } - [_button setReadingListContainsUnseenItems:NO]; +- (void)readingListModel:(const ReadingListModel*)model + didAddEntry:(const GURL&)url + entrySource:(reading_list::EntrySource)source { + if (source == reading_list::ADDED_VIA_CURRENT_APP) + [_button triggerAnimation]; } @end
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm index d31f77e..73cacaa 100644 --- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm +++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -1318,7 +1318,8 @@ } - (ToolbarModel*)toolbarModel { - return [self.delegate toolbarModelIOS]; + ToolbarModelIOS* toolbarModelIOS = [self.delegate toolbarModelIOS]; + return toolbarModelIOS ? toolbarModelIOS->GetToolbarModel() : nullptr; } #pragma mark -
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn index ba78745..c3a011be 100644 --- a/ios/chrome/test/app/BUILD.gn +++ b/ios/chrome/test/app/BUILD.gn
@@ -53,6 +53,7 @@ "//ios/chrome/browser/autofill", "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/browser_state:browser_state_impl", "//ios/chrome/browser/browsing_data", "//ios/chrome/browser/content_settings", "//ios/chrome/browser/history", @@ -61,7 +62,6 @@ "//ios/chrome/browser/signin", "//ios/chrome/browser/sync", "//ios/chrome/browser/tabs", - "//ios/chrome/browser/ui:browser_list", "//ios/chrome/browser/ui:ui_internal", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/main",
diff --git a/ios/chrome/test/app/chrome_test_util.mm b/ios/chrome/test/app/chrome_test_util.mm index 0f9fbca..9f43f5a 100644 --- a/ios/chrome/test/app/chrome_test_util.mm +++ b/ios/chrome/test/app/chrome_test_util.mm
@@ -16,10 +16,10 @@ #import "ios/chrome/app/main_controller_private.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" #import "ios/chrome/browser/metrics/previous_session_info.h" #import "ios/chrome/browser/metrics/previous_session_info_private.h" #import "ios/chrome/browser/tabs/tab.h" -#import "ios/chrome/browser/ui/browser_list_ios.h" #import "ios/chrome/browser/ui/browser_view_controller.h" #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" #import "ios/chrome/browser/ui/commands/generic_chrome_command.h" @@ -65,14 +65,17 @@ // Returns the original ChromeBrowserState if |incognito| is false. If // |ingonito| is true, returns an off-the-record ChromeBrowserState. ios::ChromeBrowserState* GetBrowserState(bool incognito) { - DCHECK(!BrowserListIOS::empty()); - id<BrowserIOS> browser = *BrowserListIOS::begin(); - DCHECK(browser); - ios::ChromeBrowserState* browser_state = [browser browserState]; - DCHECK(browser_state); - browser_state = incognito ? browser_state->GetOffTheRecordChromeBrowserState() - : browser_state->GetOriginalChromeBrowserState(); - return browser_state; + std::vector<ios::ChromeBrowserState*> browser_states = + GetApplicationContext() + ->GetChromeBrowserStateManager() + ->GetLoadedBrowserStates(); + DCHECK(!browser_states.empty()); + + ios::ChromeBrowserState* browser_state = browser_states.front(); + DCHECK(!browser_state->IsOffTheRecord()); + + return incognito ? browser_state->GetOffTheRecordChromeBrowserState() + : browser_state; } // Gets the root UIViewController.
diff --git a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn index b03ca13..95850733 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn +++ b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
@@ -17,7 +17,7 @@ "//ios/clean/chrome/browser", "//ios/clean/chrome/browser/ui/commands", "//ios/clean/chrome/browser/ui/settings", - "//ios/clean/chrome/browser/ui/tab", + "//ios/clean/chrome/browser/ui/tab_strip", "//ios/web", "//net", "//ui/base",
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm index f8406b2..2b477e3 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -17,7 +17,7 @@ #import "ios/clean/chrome/browser/ui/commands/tab_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" #import "ios/clean/chrome/browser/ui/settings/settings_coordinator.h" -#import "ios/clean/chrome/browser/ui/tab/tab_coordinator.h" +#import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.h" #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h" #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_state/web_state.h" @@ -87,7 +87,8 @@ - (void)showTabAtIndexPath:(NSIndexPath*)indexPath { DCHECK(_placeholderWebState); - TabCoordinator* tabCoordinator = [[TabCoordinator alloc] init]; + TabStripContainerCoordinator* tabCoordinator = + [[TabStripContainerCoordinator alloc] init]; tabCoordinator.webState = _placeholderWebState.get(); tabCoordinator.presentationKey = indexPath; [self addChildCoordinator:tabCoordinator];
diff --git a/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn b/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn index 1038444a..69254568 100644 --- a/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn +++ b/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn
@@ -2,6 +2,23 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +source_set("tab_strip") { + sources = [ + "tab_strip_container_coordinator.h", + "tab_strip_container_coordinator.mm", + ] + deps = [ + ":tab_strip_ui", + "//base", + "//ios/clean/chrome/browser", + "//ios/clean/chrome/browser/ui/actions", + "//ios/clean/chrome/browser/ui/animators", + "//ios/clean/chrome/browser/ui/tab", + ] + libs = [ "UIKit.framework" ] + configs += [ "//build/config/compiler:enable_arc" ] +} + source_set("tab_strip_ui") { sources = [ "tab_strip_container_view_controller.h",
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.h b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.h new file mode 100644 index 0000000..b0e05642 --- /dev/null +++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.h
@@ -0,0 +1,35 @@ +// 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. + +// ====== New Architecture ===== +// = This code is only used in the new iOS Chrome architecture. = +// ============================================================================ + +#ifndef IOS_CLEAN_CHROME_BROWSER_UI_TAB_STRIP_TAB_STRIP_CONTAINER_COORDINATOR_H_ +#define IOS_CLEAN_CHROME_BROWSER_UI_TAB_STRIP_TAB_STRIP_CONTAINER_COORDINATOR_H_ + +#import <UIKit/UIKit.h> +#import "ios/clean/chrome/browser/browser_coordinator.h" + +namespace web { +class WebState; +} + +// Coordinator that runs a tab strip container: A composed UI consisting of a +// tab strip and a tab. +@interface TabStripContainerCoordinator : BrowserCoordinator + +// The webState representing the web page that will be displayed in this tab. +// Calling code should assign this before starting this coordinator. +// This coordinator doesn't assume ownersip of |webState|. +@property(nonatomic, assign) web::WebState* webState; + +// An opaque key provided by this coordinator's parent which can be passed in +// to a transition animation to synchronize the presentation with the presenting +// view controller, if any. +@property(nonatomic, copy) NSObject* presentationKey; + +@end + +#endif // IOS_CLEAN_CHROME_BROWSER_UI_TAB_STRIP_TAB_STRIP_CONTAINER_COORDINATOR_H_
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.mm b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.mm new file mode 100644 index 0000000..889bdb8 --- /dev/null +++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.mm
@@ -0,0 +1,100 @@ +// 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. + +// ====== New Architecture ===== +// = This code is only used in the new iOS Chrome architecture. = +// ============================================================================ + +#import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_coordinator.h" + +#include <memory> + +#include "base/memory/ptr_util.h" +#import "ios/clean/chrome/browser/browser_coordinator+internal.h" +#import "ios/clean/chrome/browser/ui/actions/tab_grid_actions.h" +#import "ios/clean/chrome/browser/ui/animators/zoom_transition_animator.h" +#import "ios/clean/chrome/browser/ui/tab/tab_coordinator.h" +#import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface TabStripContainerCoordinator ()< + UIViewControllerTransitioningDelegate> +@property(nonatomic, strong) TabStripContainerViewController* viewController; +@end + +@implementation TabStripContainerCoordinator + +@synthesize webState = _webState; +@synthesize presentationKey = _presentationKey; +@synthesize viewController = _viewController; + +- (void)start { + self.viewController = [[TabStripContainerViewController alloc] init]; + self.viewController.transitioningDelegate = self; + self.viewController.modalPresentationStyle = UIModalPresentationCustom; + + TabCoordinator* tabCoordinator = [[TabCoordinator alloc] init]; + tabCoordinator.webState = self.webState; + [self addChildCoordinator:tabCoordinator]; + // Unset the root view controller, so |tabCoordinator| doesn't present + // its view controller. + tabCoordinator.rootViewController = nil; + [tabCoordinator start]; + + // PLACEHOLDER: Replace this placeholder with an actual tab strip view + // controller. + UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; + [button addTarget:nil + action:@selector(showTabGrid:) + forControlEvents:UIControlEventTouchUpInside]; + [button setTitle:@"Tab grid" forState:UIControlStateNormal]; + button.frame = CGRectMake(10, 10, 100, 100); + + UIViewController* tabStripViewController = [[UIViewController alloc] init]; + tabStripViewController.view.backgroundColor = [UIColor blackColor]; + [tabStripViewController.view addSubview:button]; + self.viewController.tabStripViewController = tabStripViewController; + self.viewController.contentViewController = tabCoordinator.viewController; + + [self.rootViewController presentViewController:self.viewController + animated:YES + completion:nil]; +} + +- (void)stop { + [self.viewController dismissViewControllerAnimated:YES completion:nil]; + self.viewController = nil; +} + +- (BOOL)canAddOverlayCoordinator:(BrowserCoordinator*)overlayCoordinator { + // This coordinator will always accept overlay coordinators. + return YES; +} + +#pragma mark - UIViewControllerTransitioningDelegate + +- (id<UIViewControllerAnimatedTransitioning>) +animationControllerForPresentedController:(UIViewController*)presented + presentingController:(UIViewController*)presenting + sourceController:(UIViewController*)source { + ZoomTransitionAnimator* animator = [[ZoomTransitionAnimator alloc] init]; + animator.presenting = YES; + animator.presentationKey = self.presentationKey; + [animator selectDelegate:@[ source, presenting ]]; + return animator; +} + +- (id<UIViewControllerAnimatedTransitioning>) +animationControllerForDismissedController:(UIViewController*)dismissed { + ZoomTransitionAnimator* animator = [[ZoomTransitionAnimator alloc] init]; + animator.presenting = NO; + animator.presentationKey = self.presentationKey; + [animator selectDelegate:@[ dismissed.presentingViewController ]]; + return animator; +} + +@end
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm index ff47f80..4afbb09 100644 --- a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm
@@ -44,7 +44,7 @@ // Called after a new strip view controller is set, but before // |-didMoveToParentViewController:| is called on that view controller. -- (void)didAddStripViewController; +- (void)didAddTabStripViewController; // Methods to populate the constraint properties. - (void)updateContentConstraintsWithStrip; @@ -87,7 +87,7 @@ [self.contentViewController didMoveToParentViewController:self]; } -- (void)setStripViewController:(UIViewController*)tabStripViewController { +- (void)setTabStripViewController:(UIViewController*)tabStripViewController { if (self.tabStripViewController == tabStripViewController) return; @@ -101,7 +101,7 @@ tabStripViewController.view.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:tabStripViewController.view]; _tabStripViewController = tabStripViewController; - [self didAddStripViewController]; + [self didAddTabStripViewController]; [self.view setNeedsUpdateConstraints]; [self.tabStripViewController didMoveToParentViewController:self]; } @@ -181,7 +181,7 @@ } } -- (void)didAddStripViewController { +- (void)didAddTabStripViewController { [self updateStripConstraints]; // If there's already a content view controller, update the constraints for // that, too.
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm index cb9ea56..5a0f3ff 100644 --- a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm +++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm
@@ -8,7 +8,7 @@ #import "ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h" -#import "ios/clean/chrome/browser/ui/actions/tab_grid_actions.h" +#import "ios/clean/chrome/browser/ui/actions/tab_strip_actions.h" #import "ios/clean/chrome/browser/ui/actions/tools_menu_actions.h" #import "ios/clean/chrome/browser/ui/commands/toolbar_commands.h" @@ -35,7 +35,7 @@ [tabSwitcher setTitle:@"⊞" forState:UIControlStateNormal]; tabSwitcher.titleLabel.font = [UIFont systemFontOfSize:24.0]; [tabSwitcher addTarget:nil - action:@selector(showTabGrid:) + action:@selector(toggleTabStrip:) forControlEvents:UIControlEventTouchUpInside]; // Placeholder omnibox.
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h index 8f5c7f19..7547b6b7 100644 --- a/ios/public/provider/chrome/browser/chrome_browser_provider.h +++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -31,6 +31,8 @@ @protocol LogoVendor; @protocol TextFieldStyling; @protocol NativeAppWhitelistManager; +@class Tab; +@class TabModel; @class UITextField; @class UIView; @protocol UrlLoader; @@ -97,6 +99,7 @@ // TODO(rohitrao): Change from |id| to |TabModel*| once TabModel is moved into // the Chromium tree. virtual void InitializeCastService(id main_tab_model) const; + virtual void InitializeCastService(TabModel* main_tab_model) const; // Attaches any embedder-specific tab helpers to the given |web_state|. The // owning |tab| is included for helpers that need access to information that @@ -104,6 +107,7 @@ // TODO(rohitrao): Change from |id| to |Tab*| once Tab is moved into the // Chromium tree. virtual void AttachTabHelpers(web::WebState* web_state, id tab) const; + virtual void AttachTabHelpers(web::WebState* web_state, Tab* tab) const; // Returns whether safe browsing is enabled. See the comment on // metrics_services_manager_client.h for details on |on_update_callback|.
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm index d771c77..9e1d496 100644 --- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm +++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -76,9 +76,23 @@ void ChromeBrowserProvider::InitializeCastService(id main_tab_model) const {} +void ChromeBrowserProvider::InitializeCastService( + TabModel* main_tab_model) const { + // Invokes the version taking an "id" as this is the only version currently + // overridden by the downstream provider. + InitializeCastService(static_cast<id>(main_tab_model)); +} + void ChromeBrowserProvider::AttachTabHelpers(web::WebState* web_state, id tab) const {} +void ChromeBrowserProvider::AttachTabHelpers(web::WebState* web_state, + Tab* tab) const { + // Invokes the version taking an "id" as this is the only version currently + // overridden by the downstream provider. + AttachTabHelpers(web_state, static_cast<id>(tab)); +} + bool ChromeBrowserProvider::IsSafeBrowsingEnabled( const base::Closure& on_update_callback) { return false;
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc index 878daf2..04636f3 100644 --- a/media/audio/audio_input_controller.cc +++ b/media/audio/audio_input_controller.cc
@@ -4,6 +4,8 @@ #include "media/audio/audio_input_controller.h" +#include <inttypes.h> + #include <algorithm> #include <limits> #include <utility> @@ -20,6 +22,7 @@ #include "media/audio/audio_file_writer.h" #include "media/base/user_input_monitor.h" +namespace media { namespace { const int kMaxInputChannels = 3; @@ -49,7 +52,7 @@ // Helper method which calculates the average power of an audio bus. Unit is in // dBFS, where 0 dBFS corresponds to all channels and samples equal to 1.0. -float AveragePower(const media::AudioBus& buffer) { +float AveragePower(const AudioBus& buffer) { const int frames = buffer.frames(); const int channels = buffer.channels(); if (frames <= 0 || channels <= 0) @@ -81,22 +84,125 @@ } // namespace -namespace media { +// Private subclass of AIC that covers the state while capturing audio. +// This class implements the callback interface from the lower level audio +// layer and gets called back on the audio hw thread. +// We implement this in a sub class instead of directly in the AIC so that +// - The AIC itself is not an AudioInputCallback. +// - The lifetime of the AudioCallback is shorter than the AIC +// - How tasks are posted to the AIC from the hw callback thread, is different +// than how tasks are posted from the AIC to itself from the main thread. +// So, this difference is isolated to the subclass (see below). +// - The callback class can gather information on what happened during capture +// and store it in a state that can be fetched after stopping capture +// (received_callback, error_during_callback). +// The AIC itself must not be AddRef-ed on the hw callback thread so that we +// can be guaranteed to not receive callbacks generated by the hw callback +// thread after Close() has been called on the audio manager thread and +// the callback object deleted. To avoid AddRef-ing the AIC and to cancel +// potentially pending tasks, we use a weak pointer to the AIC instance +// when posting. +class AudioInputController::AudioCallback + : public AudioInputStream::AudioInputCallback { + public: + explicit AudioCallback(AudioInputController* controller) + : controller_(controller), + weak_controller_(controller->weak_ptr_factory_.GetWeakPtr()) {} + ~AudioCallback() override {} + + bool received_callback() const { return received_callback_; } + bool error_during_callback() const { return error_during_callback_; } + + private: + void OnData(AudioInputStream* stream, + const AudioBus* source, + uint32_t hardware_delay_bytes, + double volume) override { + TRACE_EVENT0("audio", "AC::OnData"); + + received_callback_ = true; + + DeliverDataToSyncWriter(source, hardware_delay_bytes, volume); + PerformOptionalDebugRecording(source); + } + + void OnError(AudioInputStream* stream) override { + error_during_callback_ = true; + controller_->task_runner_->PostTask( + FROM_HERE, + base::Bind(&AudioInputController::DoReportError, weak_controller_)); + } + + void PerformOptionalDebugRecording(const AudioBus* source) { + // Called on the hw callback thread while recording is enabled. + if (!controller_->debug_writer_ || !controller_->debug_writer_->WillWrite()) + return; + + // TODO(tommi): This is costly. AudioBus heap allocs and we create a new + // one for every callback. We could instead have a pool of bus objects + // that get returned to us somehow. + // We should also avoid calling PostTask here since the implementation + // of the debug writer will basically do a PostTask straight away anyway. + // Might require some modifications to AudioInputDebugWriter though since + // there are some threading concerns there and AudioInputDebugWriter's + // lifetime guarantees need to be longer than that of associated active + // audio streams. + std::unique_ptr<AudioBus> source_copy = + AudioBus::Create(source->channels(), source->frames()); + source->CopyTo(source_copy.get()); + controller_->task_runner_->PostTask( + FROM_HERE, base::Bind(&AudioInputController::WriteInputDataForDebugging, + weak_controller_, base::Passed(&source_copy))); + } + + void DeliverDataToSyncWriter(const AudioBus* source, + uint32_t hardware_delay_bytes, + double volume) { + bool key_pressed = controller_->CheckForKeyboardInput(); + controller_->sync_writer_->Write(source, volume, key_pressed, + hardware_delay_bytes); + + // The way the two classes interact here, could be done in a nicer way. + // As is, we call the AIC here to check the audio power, return and then + // post a task to the AIC based on what the AIC said. + // The reason for this is to keep all PostTask calls from the hw callback + // thread to the AIC, that use a weak pointer, in the same class. + float average_power_dbfs; + int mic_volume_percent; + if (controller_->CheckAudioPower(source, volume, &average_power_dbfs, + &mic_volume_percent)) { + // Use event handler on the audio thread to relay a message to the ARIH + // in content which does the actual logging on the IO thread. + controller_->task_runner_->PostTask( + FROM_HERE, + base::Bind(&AudioInputController::DoLogAudioLevels, weak_controller_, + average_power_dbfs, mic_volume_percent)); + } + } + + AudioInputController* const controller_; + // We do not want any pending posted tasks generated from the callback class + // to keep the controller object alive longer than it should. So we use + // a weak ptr whenever we post, we use this weak pointer. + base::WeakPtr<AudioInputController> weak_controller_; + bool received_callback_ = false; + bool error_during_callback_ = false; +}; // static AudioInputController::Factory* AudioInputController::factory_ = nullptr; AudioInputController::AudioInputController( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, EventHandler* handler, SyncWriter* sync_writer, std::unique_ptr<AudioFileWriter> debug_writer, UserInputMonitor* user_input_monitor, const bool agc_is_enabled) : creator_task_runner_(base::ThreadTaskRunnerHandle::Get()), + task_runner_(std::move(task_runner)), handler_(handler), stream_(nullptr), - should_report_stats(0), - state_(CLOSED), sync_writer_(sync_writer), max_volume_(0.0), user_input_monitor_(user_input_monitor), @@ -107,36 +213,42 @@ silence_state_(SILENCE_STATE_NO_MEASUREMENT), #endif prev_key_down_count_(0), - debug_writer_(std::move(debug_writer)) { + debug_writer_(std::move(debug_writer)), + weak_ptr_factory_(this) { DCHECK(creator_task_runner_.get()); + DCHECK(handler_); + DCHECK(sync_writer_); } AudioInputController::~AudioInputController() { - DCHECK_EQ(state_, CLOSED); + DCHECK(!audio_callback_); + DCHECK(!stream_); } // static scoped_refptr<AudioInputController> AudioInputController::Create( AudioManager* audio_manager, EventHandler* event_handler, + SyncWriter* sync_writer, const AudioParameters& params, const std::string& device_id, UserInputMonitor* user_input_monitor) { DCHECK(audio_manager); + DCHECK(event_handler); + DCHECK(sync_writer); if (!params.IsValid() || (params.channels() > kMaxInputChannels)) return nullptr; if (factory_) { - return factory_->Create(audio_manager->GetTaskRunner(), - /*sync_writer*/ nullptr, audio_manager, - event_handler, params, user_input_monitor); + return factory_->Create(audio_manager->GetTaskRunner(), sync_writer, + audio_manager, event_handler, params, + user_input_monitor); } scoped_refptr<AudioInputController> controller(new AudioInputController( - event_handler, nullptr, nullptr, user_input_monitor, false)); - - controller->task_runner_ = audio_manager->GetTaskRunner(); + audio_manager->GetTaskRunner(), event_handler, sync_writer, nullptr, + user_input_monitor, false)); // Create and open a new audio input stream from the existing // audio-device thread. @@ -165,6 +277,7 @@ const bool agc_is_enabled) { DCHECK(audio_manager); DCHECK(sync_writer); + DCHECK(event_handler); if (!params.IsValid() || (params.channels() > kMaxInputChannels)) return nullptr; @@ -178,9 +291,8 @@ // Create the AudioInputController object and ensure that it runs on // the audio-manager thread. scoped_refptr<AudioInputController> controller(new AudioInputController( - event_handler, sync_writer, std::move(debug_writer), user_input_monitor, - agc_is_enabled)); - controller->task_runner_ = audio_manager->GetTaskRunner(); + audio_manager->GetTaskRunner(), event_handler, sync_writer, + std::move(debug_writer), user_input_monitor, agc_is_enabled)); // Create and open a new audio input stream from the existing // audio-device thread. Use the provided audio-input device. @@ -207,19 +319,19 @@ UserInputMonitor* user_input_monitor) { DCHECK(sync_writer); DCHECK(stream); + DCHECK(event_handler); if (factory_) { return factory_->Create( task_runner, sync_writer, AudioManager::Get(), event_handler, - media::AudioParameters::UnavailableDeviceParams(), user_input_monitor); + AudioParameters::UnavailableDeviceParams(), user_input_monitor); } // Create the AudioInputController object and ensure that it runs on // the audio-manager thread. scoped_refptr<AudioInputController> controller(new AudioInputController( - event_handler, sync_writer, std::move(debug_writer), user_input_monitor, - false)); - controller->task_runner_ = task_runner; + task_runner, event_handler, sync_writer, std::move(debug_writer), + user_input_monitor, false)); if (!controller->task_runner_->PostTask( FROM_HERE, @@ -233,6 +345,7 @@ } void AudioInputController::Record() { + DCHECK(creator_task_runner_->BelongsToCurrentThread()); task_runner_->PostTask(FROM_HERE, base::Bind( &AudioInputController::DoRecord, this)); } @@ -246,6 +359,7 @@ } void AudioInputController::SetVolume(double volume) { + DCHECK(creator_task_runner_->BelongsToCurrentThread()); task_runner_->PostTask(FROM_HERE, base::Bind( &AudioInputController::DoSetVolume, this, volume)); } @@ -254,9 +368,9 @@ const AudioParameters& params, const std::string& device_id) { DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!stream_); SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); - if (handler_) - handler_->OnLog(this, "AIC::DoCreate"); + handler_->OnLog(this, "AIC::DoCreate"); #if defined(AUDIO_POWER_MONITORING) // Disable power monitoring for streams that run without AGC enabled to @@ -266,6 +380,8 @@ silence_state_ = SILENCE_STATE_NO_MEASUREMENT; #endif + // MakeAudioInputStream might fail and return nullptr. If so, + // DoCreateForStream will handle and report it. DoCreateForStream(audio_manager->MakeAudioInputStream( params, device_id, base::Bind(&AudioInputController::LogMessage, this))); } @@ -289,99 +405,94 @@ void AudioInputController::DoCreateForStream( AudioInputStream* stream_to_control) { DCHECK(task_runner_->BelongsToCurrentThread()); - DCHECK(!stream_); - stream_ = stream_to_control; - should_report_stats = 1; - if (!stream_) { - if (handler_) - handler_->OnError(this, STREAM_CREATE_ERROR); + if (!stream_to_control) { LogCaptureStartupResult(CAPTURE_STARTUP_CREATE_STREAM_FAILED); + handler_->OnError(this, STREAM_CREATE_ERROR); return; } - if (stream_ && !stream_->Open()) { - stream_->Close(); - stream_ = nullptr; - if (handler_) - handler_->OnError(this, STREAM_OPEN_ERROR); + if (!stream_to_control->Open()) { + stream_to_control->Close(); LogCaptureStartupResult(CAPTURE_STARTUP_OPEN_STREAM_FAILED); + handler_->OnError(this, STREAM_OPEN_ERROR); return; } // Set AGC state using mode in |agc_is_enabled_| which can only be enabled in // CreateLowLatency(). #if defined(AUDIO_POWER_MONITORING) - bool agc_is_supported = false; - agc_is_supported = stream_->SetAutomaticGainControl(agc_is_enabled_); + bool agc_is_supported = + stream_to_control->SetAutomaticGainControl(agc_is_enabled_); // Disable power measurements on platforms that does not support AGC at a // lower level. AGC can fail on platforms where we don't support the // functionality to modify the input volume slider. One such example is // Windows XP. power_measurement_is_enabled_ &= agc_is_supported; #else - stream_->SetAutomaticGainControl(agc_is_enabled_); + stream_to_control->SetAutomaticGainControl(agc_is_enabled_); #endif - - state_ = CREATED; - if (handler_) - handler_->OnCreated(this); - - if (user_input_monitor_) { - user_input_monitor_->EnableKeyPressMonitoring(); - prev_key_down_count_ = user_input_monitor_->GetKeyPressCount(); - } + // Finally, keep the stream pointer around, update the state and notify. + stream_ = stream_to_control; + handler_->OnCreated(this); } void AudioInputController::DoRecord() { DCHECK(task_runner_->BelongsToCurrentThread()); SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); - if (state_ != CREATED) + if (!stream_ || audio_callback_) return; - { - base::AutoLock auto_lock(lock_); - state_ = RECORDING; + handler_->OnLog(this, "AIC::DoRecord"); + + if (user_input_monitor_) { + user_input_monitor_->EnableKeyPressMonitoring(); + prev_key_down_count_ = user_input_monitor_->GetKeyPressCount(); } - if (handler_) - handler_->OnLog(this, "AIC::DoRecord"); - - stream_->Start(this); + audio_callback_.reset(new AudioCallback(this)); + stream_->Start(audio_callback_.get()); } void AudioInputController::DoClose() { DCHECK(task_runner_->BelongsToCurrentThread()); SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); - // If we have already logged something, this does nothing. - // Otherwise, we haven't recieved data. - LogCaptureStartupResult(CAPTURE_STARTUP_NEVER_GOT_DATA); - if (state_ == CLOSED) + if (!stream_) return; - // If this is a low-latency stream, log the total duration (since DoCreate) - // and add it to a UMA histogram. - if (!low_latency_create_time_.is_null()) { - base::TimeDelta duration = - base::TimeTicks::Now() - low_latency_create_time_; - UMA_HISTOGRAM_LONG_TIMES("Media.InputStreamDuration", duration); - if (handler_) { - std::string log_string = - base::StringPrintf("AIC::DoClose: stream duration="); - log_string += base::Int64ToString(duration.InSeconds()); - log_string += " seconds"; - handler_->OnLog(this, log_string); + // Allow calling unconditionally and bail if we don't have a stream to close. + if (audio_callback_) { + stream_->Stop(); + + if (!low_latency_create_time_.is_null()) { + LogCaptureStartupResult(audio_callback_->received_callback() + ? CAPTURE_STARTUP_OK + : CAPTURE_STARTUP_NEVER_GOT_DATA); + UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.CallbackError", + audio_callback_->error_during_callback()); + if (audio_callback_->received_callback()) { + // Log the total duration (since DoCreate) and update the histogram. + const base::TimeDelta duration = + base::TimeTicks::Now() - low_latency_create_time_; + UMA_HISTOGRAM_LONG_TIMES("Media.InputStreamDuration", duration); + const std::string log_string = base::StringPrintf( + "AIC::DoClose: stream duration=%" PRId64 " seconds", + duration.InSeconds()); + handler_->OnLog(this, log_string); + } } + + audio_callback_.reset(); } - DoStopCloseAndClearStream(); + stream_->Close(); + stream_ = nullptr; - if (SharedMemoryAndSyncSocketMode()) - sync_writer_->Close(); + sync_writer_->Close(); if (user_input_monitor_) user_input_monitor_->DisableKeyPressMonitoring(); @@ -396,13 +507,14 @@ if (debug_writer_) debug_writer_->Stop(); - state_ = CLOSED; + max_volume_ = 0.0; + low_latency_create_time_ = base::TimeTicks(); // Reset to null. + weak_ptr_factory_.InvalidateWeakPtrs(); } void AudioInputController::DoReportError() { DCHECK(task_runner_->BelongsToCurrentThread()); - if (handler_) - handler_->OnError(this, STREAM_ERROR); + handler_->OnError(this, STREAM_ERROR); } void AudioInputController::DoSetVolume(double volume) { @@ -410,7 +522,7 @@ DCHECK_GE(volume, 0); DCHECK_LE(volume, 1.0); - if (state_ != CREATED && state_ != RECORDING) + if (!stream_) return; // Only ask for the maximum volume at first call and use cached value @@ -428,100 +540,11 @@ stream_->SetVolume(max_volume_ * volume); } -void AudioInputController::OnData(AudioInputStream* stream, - const AudioBus* source, - uint32_t hardware_delay_bytes, - double volume) { - TRACE_EVENT0("audio", "AudioInputController::OnData"); - if (debug_writer_ && debug_writer_->WillWrite()) { - std::unique_ptr<AudioBus> source_copy = - AudioBus::Create(source->channels(), source->frames()); - source->CopyTo(source_copy.get()); - task_runner_->PostTask( - FROM_HERE, - base::Bind( - &AudioInputController::WriteInputDataForDebugging, - this, - base::Passed(&source_copy))); - } - // Now we have data, so we know for sure that startup was ok. - LogCaptureStartupResult(CAPTURE_STARTUP_OK); - - { - base::AutoLock auto_lock(lock_); - if (state_ != RECORDING) - return; - } - - bool key_pressed = false; - if (user_input_monitor_) { - size_t current_count = user_input_monitor_->GetKeyPressCount(); - key_pressed = current_count != prev_key_down_count_; - prev_key_down_count_ = current_count; - DVLOG_IF(6, key_pressed) << "Detected keypress."; - } - - // Use SharedMemory and SyncSocket if the client has created a SyncWriter. - // Used by all low-latency clients except WebSpeech. - if (SharedMemoryAndSyncSocketMode()) { - sync_writer_->Write(source, volume, key_pressed, hardware_delay_bytes); - -#if defined(AUDIO_POWER_MONITORING) - // Only do power-level measurements if DoCreate() has been called. It will - // ensure that logging will mainly be done for WebRTC and WebSpeech - // clients. - if (!power_measurement_is_enabled_) - return; - - // Perform periodic audio (power) level measurements. - if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() > - kPowerMonitorLogIntervalSeconds) { - // Calculate the average power of the signal, or the energy per sample. - const float average_power_dbfs = AveragePower(*source); - - // Add current microphone volume to log and UMA histogram. - const int mic_volume_percent = static_cast<int>(100.0 * volume); - - // Use event handler on the audio thread to relay a message to the ARIH - // in content which does the actual logging on the IO thread. - task_runner_->PostTask(FROM_HERE, - base::Bind(&AudioInputController::DoLogAudioLevels, - this, - average_power_dbfs, - mic_volume_percent)); - - last_audio_level_log_time_ = base::TimeTicks::Now(); - } -#endif - return; - } - - // TODO(henrika): Investigate if we can avoid the extra copy here. - // (see http://crbug.com/249316 for details). AFAIK, this scope is only - // active for WebSpeech clients. - std::unique_ptr<AudioBus> audio_data = - AudioBus::Create(source->channels(), source->frames()); - source->CopyTo(audio_data.get()); - - // Ownership of the audio buffer will be with the callback until it is run, - // when ownership is passed to the callback function. - task_runner_->PostTask( - FROM_HERE, - base::Bind( - &AudioInputController::DoOnData, this, base::Passed(&audio_data))); -} - -void AudioInputController::DoOnData(std::unique_ptr<AudioBus> data) { - DCHECK(task_runner_->BelongsToCurrentThread()); - if (handler_) - handler_->OnData(this, data.get()); -} - void AudioInputController::DoLogAudioLevels(float level_dbfs, int microphone_volume_percent) { #if defined(AUDIO_POWER_MONITORING) DCHECK(task_runner_->BelongsToCurrentThread()); - if (!handler_) + if (!stream_) return; // Detect if the user has enabled hardware mute by pressing the mute @@ -555,14 +578,9 @@ #endif } -void AudioInputController::OnError(AudioInputStream* stream) { - // Handle error on the audio-manager thread. - task_runner_->PostTask(FROM_HERE, base::Bind( - &AudioInputController::DoReportError, this)); -} - void AudioInputController::EnableDebugRecording( const base::FilePath& file_name) { + DCHECK(creator_task_runner_->BelongsToCurrentThread()); task_runner_->PostTask( FROM_HERE, base::Bind(&AudioInputController::DoEnableDebugRecording, this, file_name)); @@ -575,20 +593,6 @@ base::Bind(&AudioInputController::DoDisableDebugRecording, this)); } -void AudioInputController::DoStopCloseAndClearStream() { - DCHECK(task_runner_->BelongsToCurrentThread()); - - // Allow calling unconditionally and bail if we don't have a stream to close. - if (stream_ != nullptr) { - stream_->Stop(); - stream_->Close(); - stream_ = nullptr; - } - - // The event handler should not be touched after the stream has been closed. - handler_ = nullptr; -} - #if defined(AUDIO_POWER_MONITORING) void AudioInputController::UpdateSilenceState(bool silence) { if (silence) { @@ -621,15 +625,8 @@ void AudioInputController::LogCaptureStartupResult( CaptureStartupResult result) { - // Decrement shall_report_stats and check if it was 1 before decrement, - // which would imply that this is the first time this method is called - // after initialization. To avoid underflow, we - // also check if should_report_stats is one before decrementing. - if (base::AtomicRefCountIsOne(&should_report_stats) && - !base::AtomicRefCountDec(&should_report_stats)) { - UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerCaptureStartupSuccess", - result, CAPTURE_STARTUP_RESULT_MAX + 1); - } + UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerCaptureStartupSuccess", + result, CAPTURE_STARTUP_RESULT_MAX + 1); } void AudioInputController::DoEnableDebugRecording( @@ -657,4 +654,45 @@ handler_->OnLog(this, message); } +bool AudioInputController::CheckForKeyboardInput() { + if (!user_input_monitor_) + return false; + + const size_t current_count = user_input_monitor_->GetKeyPressCount(); + const bool key_pressed = current_count != prev_key_down_count_; + prev_key_down_count_ = current_count; + DVLOG_IF(6, key_pressed) << "Detected keypress."; + + return key_pressed; +} + +bool AudioInputController::CheckAudioPower(const AudioBus* source, + double volume, + float* average_power_dbfs, + int* mic_volume_percent) { +#if defined(AUDIO_POWER_MONITORING) + // Only do power-level measurements if DoCreate() has been called. It will + // ensure that logging will mainly be done for WebRTC and WebSpeech + // clients. + if (!power_measurement_is_enabled_) + return false; + + // Perform periodic audio (power) level measurements. + const auto now = base::TimeTicks::Now(); + if ((now - last_audio_level_log_time_).InSeconds() <= + kPowerMonitorLogIntervalSeconds) { + return false; + } + + *average_power_dbfs = AveragePower(*source); + *mic_volume_percent = static_cast<int>(100.0 * volume); + + last_audio_level_log_time_ = now; + + return true; +#else + return false; +#endif +} + } // namespace media
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h index ef691f1..cfd6592 100644 --- a/media/audio/audio_input_controller.h +++ b/media/audio/audio_input_controller.h
@@ -11,15 +11,8 @@ #include <memory> #include <string> -#include "base/atomicops.h" -#include "base/callback.h" #include "base/files/file.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "build/build_config.h" +#include "base/memory/weak_ptr.h" #include "media/audio/audio_io.h" #include "media/audio/audio_manager_base.h" #include "media/base/audio_bus.h" @@ -55,14 +48,11 @@ // AudioInputStream::Open() // .- - - - - - - - - - - - -> OnError() // .-------------------------> OnCreated() -// kCreated // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Record() ==> DoRecord() // AudioInputStream::Start() -// kRecording // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Close() ==> DoClose() -// state_ = kClosed // AudioInputStream::Stop() // AudioInputStream::Close() // SyncWriter::Close() @@ -85,8 +75,7 @@ class UserInputMonitor; class MEDIA_EXPORT AudioInputController - : public base::RefCountedThreadSafe<AudioInputController>, - public AudioInputStream::AudioInputCallback { + : public base::RefCountedThreadSafe<AudioInputController> { public: // Error codes to make native logging more clear. These error codes are added // to generic error strings to provide a higher degree of details. @@ -114,8 +103,6 @@ virtual void OnCreated(AudioInputController* controller) = 0; virtual void OnError(AudioInputController* controller, ErrorCode error_code) = 0; - virtual void OnData(AudioInputController* controller, - const AudioBus* data) = 0; virtual void OnLog(AudioInputController* controller, const std::string& message) = 0; @@ -164,6 +151,7 @@ static scoped_refptr<AudioInputController> Create( AudioManager* audio_manager, EventHandler* event_handler, + SyncWriter* sync_writer, const AudioParameters& params, const std::string& device_id, UserInputMonitor* user_input_monitor); @@ -221,16 +209,6 @@ // to muted and 1.0 to maximum volume. virtual void SetVolume(double volume); - // AudioInputCallback implementation. Threading details depends on the - // device-specific implementation. - void OnData(AudioInputStream* stream, - const AudioBus* source, - uint32_t hardware_delay_bytes, - double volume) override; - void OnError(AudioInputStream* stream) override; - - bool SharedMemoryAndSyncSocketMode() const { return sync_writer_ != NULL; } - // Enable debug recording of audio input. virtual void EnableDebugRecording(const base::FilePath& file_name); @@ -260,13 +238,6 @@ CAPTURE_STARTUP_RESULT_MAX = CAPTURE_STARTUP_NEVER_GOT_DATA }; - // Internal state of the source. - enum State { - CREATED, - RECORDING, - CLOSED - }; - #if defined(AUDIO_POWER_MONITORING) // Used to log a silence report (see OnData). // Elements in this enum should not be deleted or rearranged; the only @@ -287,13 +258,22 @@ }; #endif - AudioInputController(EventHandler* handler, + AudioInputController(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + EventHandler* handler, SyncWriter* sync_writer, std::unique_ptr<AudioFileWriter> debug_writer, UserInputMonitor* user_input_monitor, const bool agc_is_enabled); - ~AudioInputController() override; + virtual ~AudioInputController(); + const scoped_refptr<base::SingleThreadTaskRunner>& GetTaskRunnerForTesting() + const { + return task_runner_; + } + + EventHandler* GetHandlerForTesting() const { return handler_; } + + private: // Methods called on the audio thread (owned by the AudioManager). void DoCreate(AudioManager* audio_manager, const AudioParameters& params, @@ -306,12 +286,8 @@ void DoClose(); void DoReportError(); void DoSetVolume(double volume); - void DoOnData(std::unique_ptr<AudioBus> data); void DoLogAudioLevels(float level_dbfs, int microphone_volume_percent); - // Helper method that stops, closes, and NULL:s |*stream_|. - void DoStopCloseAndClearStream(); - #if defined(AUDIO_POWER_MONITORING) // Updates the silence state, see enum SilenceState above for state // transitions. @@ -336,44 +312,49 @@ // Called by the stream with log messages. void LogMessage(const std::string& message); + // Called on the hw callback thread. Checks for keyboard input if + // user_input_monitor_ is set otherwise returns false. + bool CheckForKeyboardInput(); + + // Does power monitoring on supported platforms. + // Called on the hw callback thread. + // Returns true iff average power and mic volume was returned and should + // be posted to DoLogAudioLevels on the audio thread. + // Returns false if either power measurements are disabled or aren't needed + // right now (they're done periodically). + bool CheckAudioPower(const AudioBus* source, + double volume, + float* average_power_dbfs, + int* mic_volume_percent); + // Gives access to the task runner of the creating thread. - scoped_refptr<base::SingleThreadTaskRunner> creator_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> const creator_task_runner_; // The task runner of audio-manager thread that this object runs on. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> const task_runner_; // Contains the AudioInputController::EventHandler which receives state // notifications from this class. - EventHandler* handler_; + EventHandler* const handler_; // Pointer to the audio input stream object. + // Only used on the audio thread. AudioInputStream* stream_; - // Flag for whether CaptureStartupResults shall be reported. - // A value of 1 means that stats shall be reported, - // any other value means that stats have already been reported. - base::AtomicRefCount should_report_stats; - - // |state_| is written on the audio thread and is read on the hardware audio - // thread. These operations need to be locked. But lock is not required for - // reading on the audio input controller thread. - State state_; - - base::Lock lock_; - // SyncWriter is used only in low-latency mode for synchronous writing. - SyncWriter* sync_writer_; + SyncWriter* const sync_writer_; static Factory* factory_; double max_volume_; - UserInputMonitor* user_input_monitor_; + UserInputMonitor* const user_input_monitor_; const bool agc_is_enabled_; #if defined(AUDIO_POWER_MONITORING) - // Enabled in DoCrete() but not in DoCreateForStream(). + // Will be set to true if an AGC is supported and enabled (see DoCreate and + // DoCreateForStream). By default set to false. bool power_measurement_is_enabled_; // Updated each time a power measurement is performed. @@ -394,7 +375,29 @@ // Used for audio debug recordings. Accessed on audio thread. const std::unique_ptr<AudioFileWriter> debug_writer_; - private: + class AudioCallback; + // Holds a pointer to the callback object that receives audio data from + // the lower audio layer. Valid only while 'recording' (between calls to + // stream_->Start() and stream_->Stop()). + // The value of this pointer is only set and read on the audio thread while + // the callbacks themselves occur on the hw callback thread. More details + // in the AudioCallback class in the cc file. + std::unique_ptr<AudioCallback> audio_callback_; + + // A weak pointer factory that we use when posting tasks to the audio thread + // that we want to be automatically discarded after Close() has been called + // and that we do not want to keep the AudioInputController instance alive + // beyond what is desired by the user of the instance (e.g. + // AudioInputRendererHost). An example of where this is important is when + // we fire error notifications from the hw callback thread, post them to + // the audio thread. In that case, we do not want the error notification to + // keep the AudioInputController alive for as long as the error notification + // is pending and then make a callback from an AudioInputController that has + // already been closed. + // The weak_ptr_factory_ and all outstanding weak pointers, are invalidated + // at the end of DoClose. + base::WeakPtrFactory<AudioInputController> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(AudioInputController); };
diff --git a/media/audio/audio_input_controller_unittest.cc b/media/audio/audio_input_controller_unittest.cc index 6d44002..fdf6120 100644 --- a/media/audio/audio_input_controller_unittest.cc +++ b/media/audio/audio_input_controller_unittest.cc
@@ -8,16 +8,19 @@ #include "base/run_loop.h" #include "base/synchronization/waitable_event.h" #include "base/test/test_timeouts.h" +#include "base/threading/thread.h" #include "media/audio/audio_device_description.h" #include "media/audio/audio_input_controller.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::_; +using ::testing::AnyNumber; using ::testing::AtLeast; using ::testing::Exactly; using ::testing::InvokeWithoutArgs; using ::testing::NotNull; +using base::WaitableEvent; namespace media { @@ -53,8 +56,6 @@ MOCK_METHOD1(OnCreated, void(AudioInputController* controller)); MOCK_METHOD2(OnError, void(AudioInputController* controller, AudioInputController::ErrorCode error_code)); - MOCK_METHOD2(OnData, - void(AudioInputController* controller, const AudioBus* data)); MOCK_METHOD2(OnLog, void(AudioInputController* controller, const std::string& message)); @@ -63,23 +64,57 @@ DISALLOW_COPY_AND_ASSIGN(MockAudioInputControllerEventHandler); }; +class MockSyncWriter : public AudioInputController::SyncWriter { + public: + MockSyncWriter() {} + + MOCK_METHOD4(Write, + void(const AudioBus* data, + double volume, + bool key_pressed, + uint32_t hardware_delay_bytes)); + MOCK_METHOD0(Close, void()); +}; + // Test fixture. class AudioInputControllerTest : public testing::Test { public: AudioInputControllerTest() - : audio_manager_( - AudioManager::CreateForTesting(message_loop_.task_runner())) { - // Flush the message loop to ensure that AudioManager is fully initialized. - base::RunLoop().RunUntilIdle(); + : audio_thread_("AudioThread"), + suspend_event_(WaitableEvent::ResetPolicy::AUTOMATIC, + WaitableEvent::InitialState::NOT_SIGNALED) { + audio_thread_.StartAndWaitForTesting(); + audio_manager_ = + AudioManager::CreateForTesting(audio_thread_.task_runner()); } ~AudioInputControllerTest() override { - audio_manager_.reset(); - base::RunLoop().RunUntilIdle(); + audio_task_runner()->PostTask( + FROM_HERE, base::Bind(&AudioInputControllerTest::DeleteAudioManager, + base::Unretained(this))); + audio_thread_.Stop(); } + scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner() const { + return audio_thread_.task_runner(); + } + + void SuspendAudioThread() { + audio_task_runner()->PostTask( + FROM_HERE, base::Bind(&AudioInputControllerTest::WaitForResume, + base::Unretained(this))); + } + + void ResumeAudioThread() { suspend_event_.Signal(); } + + private: + void DeleteAudioManager() { audio_manager_.reset(); } + void WaitForResume() { suspend_event_.Wait(); } + protected: + base::Thread audio_thread_; base::MessageLoop message_loop_; ScopedAudioManagerPtr audio_manager_; + WaitableEvent suspend_event_; private: DISALLOW_COPY_AND_ASSIGN(AudioInputControllerTest); @@ -90,56 +125,59 @@ base::RunLoop run_loop; MockAudioInputControllerEventHandler event_handler; - - // OnCreated() will be posted once. - EXPECT_CALL(event_handler, OnCreated(NotNull())) - .WillOnce(QuitRunLoop(&run_loop)); + MockSyncWriter sync_writer; + scoped_refptr<AudioInputController> controller; AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout, kSampleRate, kBitsPerSample, kSamplesPerPacket); - scoped_refptr<AudioInputController> controller = AudioInputController::Create( - audio_manager_.get(), &event_handler, params, + SuspendAudioThread(); + controller = AudioInputController::Create( + audio_manager_.get(), &event_handler, &sync_writer, params, AudioDeviceDescription::kDefaultDeviceId, NULL); ASSERT_TRUE(controller.get()); + EXPECT_CALL(event_handler, OnCreated(controller.get())).Times(Exactly(1)); + EXPECT_CALL(event_handler, OnLog(controller.get(), _)); + EXPECT_CALL(sync_writer, Close()).Times(Exactly(1)); + ResumeAudioThread(); - // Wait for OnCreated() to fire. - run_loop.Run(); - - // Close the AudioInputController synchronously. CloseAudioController(controller.get()); + + audio_thread_.FlushForTesting(); } // Test a normal call sequence of create, record and close. TEST_F(AudioInputControllerTest, RecordAndClose) { MockAudioInputControllerEventHandler event_handler; + MockSyncWriter sync_writer; int count = 0; // OnCreated() will be called once. EXPECT_CALL(event_handler, OnCreated(NotNull())) .Times(Exactly(1)); - // OnData() shall be called ten times. - EXPECT_CALL(event_handler, OnData(NotNull(), NotNull())) + // Write() should be called ten times. + EXPECT_CALL(sync_writer, Write(NotNull(), _, _, _)) .Times(AtLeast(10)) - .WillRepeatedly(CheckCountAndPostQuitTask( - &count, 10, message_loop_.task_runner())); + .WillRepeatedly( + CheckCountAndPostQuitTask(&count, 10, message_loop_.task_runner())); + + EXPECT_CALL(event_handler, OnLog(_, _)).Times(AnyNumber()); + EXPECT_CALL(sync_writer, Close()).Times(Exactly(1)); AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout, kSampleRate, kBitsPerSample, kSamplesPerPacket); // Creating the AudioInputController should render an OnCreated() call. scoped_refptr<AudioInputController> controller = AudioInputController::Create( - audio_manager_.get(), &event_handler, params, + audio_manager_.get(), &event_handler, &sync_writer, params, AudioDeviceDescription::kDefaultDeviceId, NULL); ASSERT_TRUE(controller.get()); controller->Record(); - // Record and wait until ten OnData() callbacks are received. + // Record and wait until ten Write() callbacks are received. base::RunLoop().Run(); - - // Close the AudioInputController synchronously. CloseAudioController(controller.get()); } @@ -147,10 +185,10 @@ TEST_F(AudioInputControllerTest, SamplesPerPacketTooLarge) { // Create an audio device with a very large packet size. MockAudioInputControllerEventHandler event_handler; + MockSyncWriter sync_writer; // OnCreated() shall not be called in this test. - EXPECT_CALL(event_handler, OnCreated(NotNull())) - .Times(Exactly(0)); + EXPECT_CALL(event_handler, OnCreated(NotNull())).Times(Exactly(0)); AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout, @@ -158,7 +196,7 @@ kBitsPerSample, kSamplesPerPacket * 1000); scoped_refptr<AudioInputController> controller = AudioInputController::Create( - audio_manager_.get(), &event_handler, params, + audio_manager_.get(), &event_handler, &sync_writer, params, AudioDeviceDescription::kDefaultDeviceId, NULL); ASSERT_FALSE(controller.get()); } @@ -166,9 +204,13 @@ // Test calling AudioInputController::Close multiple times. TEST_F(AudioInputControllerTest, CloseTwice) { MockAudioInputControllerEventHandler event_handler; + MockSyncWriter sync_writer; // OnCreated() will be called only once. - EXPECT_CALL(event_handler, OnCreated(NotNull())); + EXPECT_CALL(event_handler, OnCreated(NotNull())).Times(Exactly(1)); + EXPECT_CALL(event_handler, OnLog(_, _)).Times(AnyNumber()); + // This callback should still only be called once. + EXPECT_CALL(sync_writer, Close()).Times(Exactly(1)); AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout, @@ -176,7 +218,7 @@ kBitsPerSample, kSamplesPerPacket); scoped_refptr<AudioInputController> controller = AudioInputController::Create( - audio_manager_.get(), &event_handler, params, + audio_manager_.get(), &event_handler, &sync_writer, params, AudioDeviceDescription::kDefaultDeviceId, NULL); ASSERT_TRUE(controller.get());
diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index e09b36e..6ab50aa 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h
@@ -94,8 +94,10 @@ // The output stream does not take ownership of this callback. virtual void Start(AudioSourceCallback* callback) = 0; - // Stops playing audio. Effect might not be instantaneous as the hardware - // might have locked audio data that is processing. + // Stops playing audio. The operation completes synchronously meaning that + // once Stop() has completed executing, no further callbacks will be made to + // the callback object that was supplied to Start() and it can be safely + // deleted. virtual void Stop() = 0; // Sets the relative volume, with range [0.0, 1.0] inclusive.
diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc index 097e4c9a..30430bf 100644 --- a/media/audio/audio_manager.cc +++ b/media/audio/audio_manager.cc
@@ -303,6 +303,10 @@ scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, AudioLogFactory* audio_log_factory); +void AudioManager::SetMaxStreamCountForTesting(int max_input, int max_output) { + NOTREACHED(); +} + AudioManager::AudioManager( scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner)
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index 6563251..c5a7cdd 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h
@@ -251,6 +251,9 @@ // Gets the name of the audio manager (e.g., Windows, Mac, PulseAudio). virtual const char* GetName() = 0; + // Limits the number of streams that can be created for testing purposes. + virtual void SetMaxStreamCountForTesting(int max_input, int max_output); + protected: AudioManager(scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner);
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index dd6e9a2a..670820d 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc
@@ -433,4 +433,10 @@ return audio_log_factory_->CreateAudioLog(component); } +void AudioManagerBase::SetMaxStreamCountForTesting(int max_input, + int max_output) { + max_num_output_streams_ = max_output; + max_num_input_streams_ = max_input; +} + } // namespace media
diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index 4dc3fd3f..b3100cf6 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h
@@ -68,6 +68,8 @@ std::unique_ptr<AudioLog> CreateAudioLog( AudioLogFactory::AudioComponent component) override; + void SetMaxStreamCountForTesting(int max_input, int max_output) final; + // AudioManagerBase: // Called internally by the audio stream when it has been closed.
diff --git a/media/audio/test_audio_input_controller_factory.cc b/media/audio/test_audio_input_controller_factory.cc index fb70e32a..1766b925 100644 --- a/media/audio/test_audio_input_controller_factory.cc +++ b/media/audio/test_audio_input_controller_factory.cc
@@ -15,16 +15,16 @@ EventHandler* event_handler, SyncWriter* sync_writer, UserInputMonitor* user_input_monitor) - : AudioInputController(event_handler, + : AudioInputController(audio_manager->GetTaskRunner(), + event_handler, sync_writer, nullptr, user_input_monitor, false), audio_parameters_(audio_parameters), factory_(factory), - event_handler_(event_handler) { - task_runner_ = audio_manager->GetTaskRunner(); -} + event_handler_(event_handler), + sync_writer_(sync_writer) {} TestAudioInputController::~TestAudioInputController() { // Inform the factory so that it allows creating new instances in future. @@ -37,7 +37,7 @@ } void TestAudioInputController::Close(const base::Closure& closed_task) { - task_runner_->PostTask(FROM_HERE, closed_task); + GetTaskRunnerForTesting()->PostTask(FROM_HERE, closed_task); if (factory_->delegate_) factory_->delegate_->TestAudioControllerClosed(this); } @@ -59,8 +59,9 @@ AudioParameters params, UserInputMonitor* user_input_monitor) { DCHECK(!controller_); // Only one test instance managed at a time. - controller_ = new TestAudioInputController( - this, audio_manager, params, event_handler, NULL, user_input_monitor); + controller_ = + new TestAudioInputController(this, audio_manager, params, event_handler, + sync_writer, user_input_monitor); return controller_; }
diff --git a/media/audio/test_audio_input_controller_factory.h b/media/audio/test_audio_input_controller_factory.h index 4a04d36e..90f81b7f 100644 --- a/media/audio/test_audio_input_controller_factory.h +++ b/media/audio/test_audio_input_controller_factory.h
@@ -65,6 +65,9 @@ // Returns the event handler installed on the AudioInputController. EventHandler* event_handler() const { return event_handler_; } + // Returns a pointer to the audio callback for the AudioInputController. + SyncWriter* sync_writer() const { return sync_writer_; } + // Notifies the TestAudioControllerOpened() event to the delegate (if any). void Record() override; @@ -84,7 +87,8 @@ // These are not owned by us and expected to be valid for this object's // lifetime. TestAudioInputControllerFactory* factory_; - EventHandler* event_handler_; + EventHandler* const event_handler_; + SyncWriter* const sync_writer_; DISALLOW_COPY_AND_ASSIGN(TestAudioInputController); };
diff --git a/remoting/host/win/BUILD.gn b/remoting/host/win/BUILD.gn index f6ddd335..80e3a38 100644 --- a/remoting/host/win/BUILD.gn +++ b/remoting/host/win/BUILD.gn
@@ -276,10 +276,12 @@ "entry_point.cc", ] - ldflags = [ - "/ENTRY:HostEntryPoint", - # "/NODEFAULTLIB", - ] + if (!is_asan) { + ldflags = [ + "/ENTRY:HostEntryPoint", + # "/NODEFAULTLIB", + ] + } } executable("remoting_me2me_host") { @@ -304,7 +306,12 @@ output_name = "remoting_host" - ldflags = [ "/ENTRY:HostEntryPoint" ] + if (!is_asan) { + ldflags = [ + "/ENTRY:HostEntryPoint", + # "/NODEFAULTLIB", + ] + } } shared_library("remoting_core") { @@ -440,10 +447,12 @@ "entry_point.cc", ] - ldflags = [ - "/ENTRY:HostEntryPoint", - # "/NODEFAULTLIB", - ] + if (!is_asan) { + ldflags = [ + "/ENTRY:HostEntryPoint", + # "/NODEFAULTLIB", + ] + } } executable("remoting_native_messaging_host") {
diff --git a/remoting/host/win/entry_point.cc b/remoting/host/win/entry_point.cc index 0d711f2..a4e1f10 100644 --- a/remoting/host/win/entry_point.cc +++ b/remoting/host/win/entry_point.cc
@@ -14,3 +14,21 @@ int exit_code = remoting::HostMain(0, nullptr); ExitProcess(exit_code); } + +#if defined(ADDRESS_SANITIZER) +// Executables instrumented with ASAN need CRT functions. We do not use +// the /ENTRY switch for ASAN instrumented executable and a "main" function +// is required. +int WINAPI wWinMain (HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) { + HostEntryPoint(); + return 0; +} + +int wmain() { + HostEntryPoint(); + return 0; +} +#endif
diff --git a/services/ui/ime/ime_server_impl.cc b/services/ui/ime/ime_server_impl.cc index 0731d02..a5a10d37 100644 --- a/services/ui/ime/ime_server_impl.cc +++ b/services/ui/ime/ime_server_impl.cc
@@ -4,6 +4,7 @@ #include "services/ui/ime/ime_server_impl.h" +#include "base/memory/ptr_util.h" #include "services/catalog/public/interfaces/constants.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "services/ui/ime/ime_registrar_impl.h" @@ -46,26 +47,20 @@ driver_ = std::move(driver); while (!pending_requests_.empty()) { - driver_->StartSession(current_id_++, - std::move(pending_requests_.front().first), - std::move(pending_requests_.front().second)); + driver_->StartSession(current_id_++, std::move(pending_requests_.front())); pending_requests_.pop(); } } -void IMEServerImpl::StartSession( - mojom::TextInputClientPtr client, - mojom::InputMethodRequest input_method_request) { +void IMEServerImpl::StartSession(mojom::StartSessionDetailsPtr details) { if (driver_.get()) { // TODO(moshayedi): crbug.com/634431. This will forward all calls from // clients to the driver as they are. We may need to check |caret_bounds| // parameter of InputMethod::OnCaretBoundsChanged() here and limit them to // client's focused window. - driver_->StartSession(current_id_++, std::move(client), - std::move(input_method_request)); + driver_->StartSession(current_id_++, std::move(details)); } else { - pending_requests_.push( - std::make_pair(std::move(client), std::move(input_method_request))); + pending_requests_.push(std::move(details)); } }
diff --git a/services/ui/ime/ime_server_impl.h b/services/ui/ime/ime_server_impl.h index 22156cb..76cc5a8 100644 --- a/services/ui/ime/ime_server_impl.h +++ b/services/ui/ime/ime_server_impl.h
@@ -28,8 +28,7 @@ private: // mojom::IMEServer: - void StartSession(mojom::TextInputClientPtr client, - mojom::InputMethodRequest input_method) override; + void StartSession(mojom::StartSessionDetailsPtr details) override; void OnGotCatalogEntries(std::vector<catalog::mojom::EntryPtr> entries); @@ -39,9 +38,7 @@ mojom::IMEDriverPtr driver_; int current_id_; - using PendingRequest = - std::pair<mojom::TextInputClientPtr, mojom::InputMethodRequest>; - std::queue<PendingRequest> pending_requests_; + std::queue<mojom::StartSessionDetailsPtr> pending_requests_; DISALLOW_COPY_AND_ASSIGN(IMEServerImpl); };
diff --git a/services/ui/ime/ime_unittest.cc b/services/ui/ime/ime_unittest.cc index 121cdc1..582521f 100644 --- a/services/ui/ime/ime_unittest.cc +++ b/services/ui/ime/ime_unittest.cc
@@ -93,7 +93,11 @@ TestTextInputClient client(MakeRequest(&client_ptr)); ui::mojom::InputMethodPtr input_method; - ime_server_->StartSession(std::move(client_ptr), MakeRequest(&input_method)); + ui::mojom::StartSessionDetailsPtr details = + ui::mojom::StartSessionDetails::New(); + details->client = std::move(client_ptr); + details->input_method_request = MakeRequest(&input_method); + ime_server_->StartSession(std::move(details)); // Send character key event. ui::KeyEvent char_event('A', ui::VKEY_A, 0);
diff --git a/services/ui/ime/test_ime_driver/test_ime_driver.cc b/services/ui/ime/test_ime_driver/test_ime_driver.cc index 5003640..613d103e 100644 --- a/services/ui/ime/test_ime_driver/test_ime_driver.cc +++ b/services/ui/ime/test_ime_driver/test_ime_driver.cc
@@ -41,14 +41,12 @@ TestIMEDriver::~TestIMEDriver() {} -void TestIMEDriver::StartSession( - int32_t session_id, - mojom::TextInputClientPtr client, - mojom::InputMethodRequest input_method_request) { +void TestIMEDriver::StartSession(int32_t session_id, + mojom::StartSessionDetailsPtr details) { input_method_bindings_[session_id].reset( new mojo::Binding<mojom::InputMethod>( - new TestInputMethod(std::move(client)), - std::move(input_method_request))); + new TestInputMethod(std::move(details->client)), + std::move(details->input_method_request))); } void TestIMEDriver::CancelSession(int32_t session_id) {
diff --git a/services/ui/ime/test_ime_driver/test_ime_driver.h b/services/ui/ime/test_ime_driver/test_ime_driver.h index 30fcd5360..3e26953a 100644 --- a/services/ui/ime/test_ime_driver/test_ime_driver.h +++ b/services/ui/ime/test_ime_driver/test_ime_driver.h
@@ -23,10 +23,8 @@ private: // ui::mojom::IMEDriver: - void StartSession( - int32_t session_id, - ui::mojom::TextInputClientPtr client, - ui::mojom::InputMethodRequest input_method_request) override; + void StartSession(int32_t session_id, + ui::mojom::StartSessionDetailsPtr details) override; void CancelSession(int32_t session_id) override; std::map<int32_t, std::unique_ptr<mojo::Binding<mojom::InputMethod>>>
diff --git a/services/ui/public/interfaces/ime/BUILD.gn b/services/ui/public/interfaces/ime/BUILD.gn index 3a60f3f..85909fb 100644 --- a/services/ui/public/interfaces/ime/BUILD.gn +++ b/services/ui/public/interfaces/ime/BUILD.gn
@@ -10,6 +10,7 @@ ] public_deps = [ + "//mojo/common:common_custom_types", "//ui/events/mojo:interfaces", "//ui/gfx/geometry/mojo", "//ui/gfx/range/mojo",
diff --git a/services/ui/public/interfaces/ime/ime.mojom b/services/ui/public/interfaces/ime/ime.mojom index d491da3..c122750 100644 --- a/services/ui/public/interfaces/ime/ime.mojom +++ b/services/ui/public/interfaces/ime/ime.mojom
@@ -4,6 +4,7 @@ module ui.mojom; +import "mojo/common/text_direction.mojom"; import "ui/events/mojo/event.mojom"; import "ui/gfx/geometry/mojo/geometry.mojom"; import "ui/gfx/range/mojo/range.mojom"; @@ -64,14 +65,26 @@ URL, }; +// Parameters needed to start an IME session. +struct StartSessionDetails { + TextInputClient client; + InputMethod& input_method_request; + + // Initial details about |client| required by IMEDriver. + TextInputType text_input_type; + TextInputMode text_input_mode; + mojo.common.mojom.TextDirection text_direction; + int32 text_input_flags; + gfx.mojom.Rect caret_bounds; +}; + // A service which provides the IMEDriver interface is responsible for doing // the composition logic. After starting a session, it receives events from // the client via the InputMethod interface, and sends composition events to // the client via the TextInputClient. interface IMEDriver { // session_id is unique and generated by Mus. - StartSession(int32 session_id, TextInputClient client, - InputMethod& input_method); + StartSession(int32 session_id, StartSessionDetails details); CancelSession(int32 session_id); }; @@ -79,8 +92,7 @@ // does minimal processing and mostly just acts as lightweight proxy between // the client app and the registered IME driver. interface IMEServer { - StartSession(TextInputClient client, - InputMethod& input_method); + StartSession(StartSessionDetails details); }; // An IME driver register should register itself to Mus using the IMERegistrar
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index d26c1d3e..5d3b758 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -829,6 +829,25 @@ ] } ], + "HttpFormWarning": [ + { + "platforms": [ + "android", + "chromeos", + "linux", + "mac", + "win" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "HttpFormWarning" + ] + } + ] + } + ], "IOSurfaceClearYosemite": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index 875d507..10607bf0 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -588,6 +588,7 @@ Bug(none) fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-squashing.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-trigger-commit.html [ Failure ] +Bug(none) fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects.html [ Failure ] Bug(none) fast/events/touch/gesture/gesture-scroll-by-page.html [ Failure ] Bug(none) fast/events/touch/gesture/gesture-scroll-by-pixel.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index bf5e4ec..ac42e3d2 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -340,7 +340,7 @@ # imported/wpt/user-timing [ Pass ] imported/wpt/vibration [ Skip ] ## Owners: bsheedy@chromium.org -# imported/wpt/vr [ Pass ] +# imported/wpt/webvr [ Pass ] imported/wpt/wai-aria [ Skip ] ## Owners: suzyh@chromium.org # imported/wpt/web-animations [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/animations/pause-paused-animation-for-testing.html b/third_party/WebKit/LayoutTests/animations/pause-paused-animation-for-testing.html new file mode 100644 index 0000000..ba6364b --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/pause-paused-animation-for-testing.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<style> +@keyframes test {} +#target { + animation: test 1s paused; +} +</style> +<div id="target"></div> +<script> +test(() => { + internals.pauseAnimations(0); +}, 'Do not crash when pausing a paused animation for testing'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-constructor.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-constructor.html new file mode 100644 index 0000000..3ec49e4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-constructor.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/canvas-Float32ImageData.js"></script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-workers.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-workers.html new file mode 100644 index 0000000..b3c97567 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-Float32ImageData-workers.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +fetch_tests_from_worker(new Worker("resources/canvas-Float32ImageData-workers.js")); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-constructor-expected.txt index f1b473d..77d93449 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-constructor-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-constructor-expected.txt
@@ -18,16 +18,16 @@ PASS new ImageData(1 << 31, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS new ImageData(new Uint8ClampedArray(0)) threw exception TypeError: Failed to construct 'ImageData': 2 arguments required, but only 1 present.. PASS new ImageData(new Uint8Array(100), 25) threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS new ImageData(new Uint8ClampedArray(27), 2) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of 4.. -PASS new ImageData(new Uint8ClampedArray(28), 7, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not equal to (4 * width * height).. -PASS new ImageData(new Uint8ClampedArray(104), 14) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS new ImageData(new Uint8ClampedArray(27), 2) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of 4.. +PASS new ImageData(new Uint8ClampedArray(28), 7, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The source height is zero or not a number.. +PASS new ImageData(new Uint8ClampedArray(104), 14) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).. PASS new ImageData(self, 4, 4) threw exception TypeError: Failed to construct 'ImageData': parameter 1 is not of type 'Uint8ClampedArray'.. PASS new ImageData(null, 4, 4) threw exception TypeError: Failed to construct 'ImageData': parameter 1 is not of type 'Uint8ClampedArray'.. PASS new ImageData(imageData.data, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS new ImageData(imageData.data, 13) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. -PASS new ImageData(imageData.data, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS new ImageData(imageData.data, 13) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).. +PASS new ImageData(imageData.data, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS new ImageData(imageData.data, 'biggish') threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS new ImageData(imageData.data, 1 << 24, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS new ImageData(imageData.data, 1 << 24, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS (new ImageData(new Uint8ClampedArray(28), 7)).height is 1 PASS imageDataFromData.width is 100 PASS imageDataFromData.height is 50
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-workers-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-workers-expected.txt index 51185d7..8f444dd 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-workers-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageData-workers-expected.txt
@@ -19,16 +19,16 @@ PASS [Worker] new ImageData(1 << 31, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS [Worker] new ImageData(new Uint8ClampedArray(0)) threw exception TypeError: Failed to construct 'ImageData': 2 arguments required, but only 1 present.. PASS [Worker] new ImageData(new Uint8Array(100), 25) threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS [Worker] new ImageData(new Uint8ClampedArray(27), 2) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of 4.. -PASS [Worker] new ImageData(new Uint8ClampedArray(28), 7, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not equal to (4 * width * height).. -PASS [Worker] new ImageData(new Uint8ClampedArray(104), 14) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS [Worker] new ImageData(new Uint8ClampedArray(27), 2) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of 4.. +PASS [Worker] new ImageData(new Uint8ClampedArray(28), 7, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The source height is zero or not a number.. +PASS [Worker] new ImageData(new Uint8ClampedArray(104), 14) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).. PASS [Worker] new ImageData(self, 4, 4) threw exception TypeError: Failed to construct 'ImageData': parameter 1 is not of type 'Uint8ClampedArray'.. PASS [Worker] new ImageData(null, 4, 4) threw exception TypeError: Failed to construct 'ImageData': parameter 1 is not of type 'Uint8ClampedArray'.. PASS [Worker] new ImageData(imageData.data, 0) threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS [Worker] new ImageData(imageData.data, 13) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. -PASS [Worker] new ImageData(imageData.data, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS [Worker] new ImageData(imageData.data, 13) threw exception IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of (4 * width).. +PASS [Worker] new ImageData(imageData.data, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS [Worker] new ImageData(imageData.data, 'biggish') threw exception IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.. -PASS [Worker] new ImageData(imageData.data, 1 << 24, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The input data byte length is not a multiple of (4 * width).. +PASS [Worker] new ImageData(imageData.data, 1 << 24, 1 << 31) threw exception IndexSizeError: Failed to construct 'ImageData': The requested image size exceeds the supported range.. PASS [Worker] (new ImageData(new Uint8ClampedArray(28), 7)).height is 1 PASS [Worker] imageDataFromData.width is 100 PASS [Worker] imageDataFromData.height is 50
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/float32ImageData-colorSpace.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/float32ImageData-colorSpace.html new file mode 100644 index 0000000..5731c30 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/float32ImageData-colorSpace.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<body> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + +// RGBA(255,0,0,255) -> LinearRGB(0x3c00, 0x0, 0x0, 0x3c00) +var data = new Float32Array([0x00003c00, 0x0, 0x0, 0x00003c00]); + +test(function() { + + assert_equals((new Float32ImageData(1, 1)).colorSpace, "linear-rgb", "The default color space for Float32ImageData is linear-rgb."); + assert_equals((new Float32ImageData(1, 1, "linear-rgb")).colorSpace, "linear-rgb", "The color space read from Float32ImageData is the one that was set."); + assert_throws("NotSupportedError", function() {fImageData = new Float32ImageData(1, 1, "legacy-srgb");}, "Legacy SRGB is not supported in Float32ImageData."); + assert_throws("NotSupportedError", function() {fImageData = new Float32ImageData(1, 1, "srgb");}, "SRGB is not supported in Float32ImageData."); + assert_throws(null, function() {fImageData = new Float32ImageData(1, 1, "undefined");}, "Only members of ImageDataColorSpace enum are processed in Float32ImageData constructor."); + + assert_equals((new Float32ImageData(data, 1, 1)).colorSpace, "linear-rgb", "The default color space for Float32ImageData is linear-rgb."); + assert_equals((new Float32ImageData(data, 1, 1, "linear-rgb")).colorSpace, "linear-rgb", "The color space read from Float32ImageData is the one that was set."); + assert_throws("NotSupportedError", function() {fImageData = new Float32ImageData(data, 1, 1, "legacy-srgb");}, "Legacy SRGB is not supported in Float32ImageData."); + assert_throws("NotSupportedError", function() {fImageData = new Float32ImageData(data, 1, 1, "srgb");}, "SRGB is not supported in Float32ImageData."); + assert_throws(null, function() {fImageData = new Float32ImageData(data, 1, 1, "undefined");}, "Only members of ImageDataColorSpace enum are processed in Float32ImageData constructor."); + +}, 'This test examines the correct behavior of Float32ImageData API in setting and getting ImageDataColorSpace.'); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/imageData-colorSpace.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/imageData-colorSpace.html new file mode 100644 index 0000000..a170bc6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/imageData-colorSpace.html
@@ -0,0 +1,49 @@ +<!DOCTYPE html> +<body> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + +var data = new Uint8ClampedArray([255, 0, 0, 255]); + +function createImageDataAndGetColorSpace(colorSpace) { + experimental = new ImageData(1,1); + imageData = experimental.createImageData(1, 1, colorSpace) + return imageData.colorSpace; +} + +function createWithDataAndGetColorSpaceW(colorSpace) { + experimental = new ImageData(1,1); + imageData = experimental.createImageData(data, 1, colorSpace) + return imageData.colorSpace; +} + +function createWithDataAndGetColorSpaceWH(colorSpace) { + experimental = new ImageData(1,1); + imageData = experimental.createImageData(data, 1, 1, colorSpace) + return imageData.colorSpace; +} + +test(function() { + assert_equals((new ImageData(1,1)).colorSpace, "legacy-srgb", "The default color space for ImageData is legacy-srgb."); + assert_equals(createImageDataAndGetColorSpace("legacy-srgb"), "legacy-srgb", "The color space read from ImageData is the one that was set."); + assert_equals(createImageDataAndGetColorSpace("srgb"), "srgb", "The color space read from ImageData is the one that was set."); + assert_throws("NotSupportedError", function() {createImageDataAndGetColorSpace("linear-rgb");}, "Linear RGB is not supported in ImageData."); + assert_throws(null, function() {createImageDataAndGetColorSpace("undefined");}, "Only members of ImageDataColorSpace enum are processed in ImageData constructor."); + + assert_equals((new ImageData(data,1)).colorSpace, "legacy-srgb", "The default color space for ImageData is legacy-srgb."); + assert_equals(createWithDataAndGetColorSpaceW("legacy-srgb"), "legacy-srgb", "The color space read from ImageData is the one that was set."); + assert_equals(createWithDataAndGetColorSpaceW("srgb"), "srgb", "The color space read from ImageData is the one that was set."); + assert_throws("NotSupportedError", function() {createWithDataAndGetColorSpaceW("linear-rgb");}, "Linear RGB is not supported in ImageData."); + assert_throws(null, function() {createWithDataAndGetColorSpaceW("undefined");}, "Only members of ImageDataColorSpace enum are processed in ImageData constructor."); + + assert_equals((new ImageData(data,1, 1)).colorSpace, "legacy-srgb", "The default color space for ImageData is legacy-srgb."); + assert_equals(createWithDataAndGetColorSpaceWH("legacy-srgb"), "legacy-srgb", "The color space read from ImageData is the one that was set."); + assert_equals(createWithDataAndGetColorSpaceWH("srgb"), "srgb", "The color space read from ImageData is the one that was set."); + assert_throws("NotSupportedError", function() {createWithDataAndGetColorSpaceWH("linear-rgb");}, "Linear RGB is not supported in ImageData."); + assert_throws(null, function() {createWithDataAndGetColorSpaceWH("undefined");}, "Only members of ImageDataColorSpace enum are processed in ImageData constructor."); + +}, 'This test examines the correct behavior of createImageData API in setting and getting ImageData.colorSpace.'); + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData-workers.js b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData-workers.js new file mode 100644 index 0000000..7c872b55 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData-workers.js
@@ -0,0 +1,2 @@ +importScripts('../../../resources/testharness.js', 'canvas-Float32ImageData.js'); +done();
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData.js b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData.js new file mode 100644 index 0000000..838297b0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-Float32ImageData.js
@@ -0,0 +1,121 @@ +function setF16Color(float32ImageData, i, f16Color) { + var s = i * 4; + float32ImageData[s] = f16Color[0]; + float32ImageData[s + 1] = f16Color[1]; + float32ImageData[s + 2] = f16Color[2]; + float32ImageData[s + 3] = f16Color[3]; +} + +function getF16Color(float32ImageData, i) { + var result = []; + var s = i * 4; + for (var j = 0; j < 4; j++) { + result[j] = float32ImageData[s + j]; + } + return result; +} + +function compareF16Colors(f16Color1, f16Color2) { + for (var j = 0; j < 4; j++) + if (f16Color1[j] != f16Color2[j]) + return false; + return true; +} + +test(function() { + + float32ImageData = new Float32ImageData(100, 50); + assert_equals(float32ImageData.width, 100, + "The width of the float32ImageData should be the width we passed to the constructor."); + assert_equals(float32ImageData.height, 50, + "The height of the float32ImageData should be the height we passed to the constructor."); + + var f16ColorData = getF16Color(float32ImageData.data, 4); + assert_equals(f16ColorData[0], 0, + "The default ImageData color is transparent black."); + assert_equals(f16ColorData[1], 0, + "The default ImageData color is transparent black."); + assert_equals(f16ColorData[2], 0, + "The default ImageData color is transparent black."); + assert_equals(f16ColorData[3], 0, + "The default ImageData color is transparent black."); + + var testColor = new Float32Array([0x00003c00, 0x00003c01, 0x00003c02, 0x00003c03]); + setF16Color(float32ImageData.data, 4, testColor); + f16ColorData = getF16Color(float32ImageData.data, 4); + assert_equals(f16ColorData[0], 0x00003c00, + "The red component of f16 color is the value we set."); + assert_equals(f16ColorData[1], 0x00003c01, + "The green component of f16 color is the value we set."); + assert_equals(f16ColorData[2], 0x00003c02, + "The blue component of f16 color is the value we set."); + assert_equals(f16ColorData[3], 0x00003c03, + "The alpha component of f16 color is the value we set."); + + assert_throws(null, function() {new Float32ImageData(10);}, + "Float32ImageData constructor requires both width and height."); + assert_throws("IndexSizeError", function() {new Float32ImageData(0,10);}, + "Float32ImageData width must be greater than zero."); + assert_throws("IndexSizeError", function() {new Float32ImageData(10,0);}, + "Float32ImageData height must be greater than zero."); + assert_throws("IndexSizeError", function() {new Float32ImageData('width', 'height');}, + "Float32ImageData width and height must be numbers."); + assert_throws("IndexSizeError", function() {new Float32ImageData(1 << 31, 1 << 31);}, + "Float32ImageData width multiplied by height must be less than 2^30 to avoid buffer size overflow."); + + assert_throws(null, function() {new Float32ImageData(new Float32Array(0));}, + "The Float32Array passed to the constructor cannot have a length of zero."); + assert_throws("IndexSizeError", function() {new Float32ImageData(new Float32Array(27), 2);}, + "The size of Float32Array passed to the constructor must be divisible by 4 * width."); + assert_throws("IndexSizeError", function() {new Float32ImageData(new Float32Array(28), 7, 0);}, + "The size of Float32Array passed to the constructor must be equal to 4 * width * height."); + assert_throws(null, function() {new Float32ImageData(self, 4, 4);}, + "The object passed to the constructor as data array should be of type Float32Array."); + assert_throws(null, function() {new Float32ImageData(null, 4, 4);}, + "The object passed to the constructor as data array should be of type Float32Array."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 0);}, + "The size of Float32Array passed to the constructor must be divisible by 4 * width."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 13);}, + "The size of Float32Array passed to the constructor must be divisible by 4 * width."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 1 << 31);}, + "The size of Float32Array passed to the constructor must be divisible by 4 * width."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 'biggish');}, + "The width parameter must be a number."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 1 << 24, 1 << 31);}, + "Float32ImageData width multiplied by height must be less than 2^30 to avoid buffer size overflow."); + assert_throws("IndexSizeError", function() {new Float32ImageData(float32ImageData.data, 1 << 31, 1 << 24);}, + "Float32ImageData width multiplied by height must be less than 2^30 to avoid buffer size overflow."); + assert_equals((new Float32ImageData(new Float32Array(28), 7)).height, 1, + "The height must be equal to size of the data array divided by 4 * width."); + + float32ImageDataFromData = new Float32ImageData(float32ImageData.data, 100); + assert_equals(float32ImageDataFromData.width, 100, + "The width of the float32ImageDataFromData should be the same as that of float32ImageData."); + assert_equals(float32ImageDataFromData.height, 50, + "The height of the float32ImageDataFromData should be the same as that of float32ImageData."); + assert_true(float32ImageDataFromData.data == float32ImageData.data, + "The pixel data buffer of float32ImageDataFromData should be the same as that of float32ImageData."); + assert_true(compareF16Colors(getF16Color(float32ImageDataFromData.data, 10), + getF16Color(float32ImageData.data, 10)), + "The color of a pixel from float32ImageDataFromData should be the same as that of float32ImageData."); + setF16Color(float32ImageData.data, 10, testColor); + assert_true(compareF16Colors(getF16Color(float32ImageDataFromData.data, 10), + getF16Color(float32ImageData.data, 10)), + "Setting the color of a pixel from float32ImageData must cascade to the same pixel of float32ImageDataFromData."); + + var data = new Float32Array(400); + data[22] = 129; + float32ImageDataFromData = new Float32ImageData(data, 20, 5); + assert_equals(float32ImageDataFromData.width, 20, + "The width of the float32ImageData should be the width we passed to the constructor."); + assert_equals(float32ImageDataFromData.height, 5, + "The height of the Float32ImageData must be equal to size of the Float32Array divided by 4 * width."); + assert_true(float32ImageDataFromData.data == data, + "The pixel data buffer of float32ImageDataFromData should be the same buffer passed to the constructor."); + assert_true(compareF16Colors(getF16Color(float32ImageDataFromData.data, 2), getF16Color(data, 2)), + "The pixel data of float32ImageDataFromData should be the same as that of the buffer passed to the constructor."); + setF16Color(float32ImageDataFromData.data, 2, testColor); + assert_true(compareF16Colors(getF16Color(float32ImageDataFromData.data, 2), getF16Color(data, 2)), + "Setting the color of a pixel from float32ImageDataFromData must cascade to the same pixel of the buffer passed to the constructor."); + +}, 'This test examines the correct behavior of Float32ImageData API.');
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfacesetloadevent-constructor.html b/third_party/WebKit/LayoutTests/fast/css/fontfacesetloadevent-constructor.html new file mode 100644 index 0000000..940d601 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/fontfacesetloadevent-constructor.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>FontFaceSetLoadEvent Constructor</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + test(function() { + var ff = []; + var e = new FontFaceSetLoadEvent('type'); + assert_array_equals(e.fontfaces, ff); + assert_not_equals(e.fontfaces, ff); + }, 'Test FontFaceSetLoadEvent constructor without FontFaceSetLoadEventInit dictionary'); + + test(function() { + var ff = [ new FontFace('family', 'src') ]; + var e = new FontFaceSetLoadEvent('type', { fontfaces: ff }); + assert_array_equals(e.fontfaces, ff); + assert_not_equals(e.fontfaces, ff); + }, 'Test FontFaceSetLoadEvent constructor with FontFaceSetLoadEventInit dictionary'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt new file mode 100644 index 0000000..29f4ce2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt
@@ -0,0 +1,7 @@ +This test verifies the touch event target rects are updated correctly when an element transfroms without causing layout. + +[object HTMLDivElement]: #document (100, 100, 50, 50) + +[object HTMLDivElement]: #document (150, 100, 50, 50) + +
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html new file mode 100644 index 0000000..80f0b5b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<style> +#box { + position: absolute; + top: 100px; + left: 100px; + width: 50px; + height: 50px; + background-color: blue; +} +</style> + +<p id="description"> +This test verifies the touch event target rects are updated correctly when +an element transfroms without causing layout. +</p> + +<div id="tests"> + <div id="box"></div> +</div> +<div id="console" style="display:none;"></div> + +<script src="resources/compositor-touch-hit-rects.js"></script> +<script> + +const box = document.getElementById("box"); +box.addEventListener("touchstart", () => {}, false); +internals.forceCompositingUpdate(document); +logRects(box, true); + +// The box should be able to translate to a new location +box.style.transform = "translate(50px,0px)"; +internals.forceCompositingUpdate(document); +logRects(box, true); + +document.getElementById("console").style.display = "block"; + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/performance/longtasktiming.html b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-attributes.html similarity index 100% rename from third_party/WebKit/LayoutTests/fast/performance/longtasktiming.html rename to third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-attributes.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-externalscript.html b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-externalscript.html new file mode 100644 index 0000000..95334f21 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-externalscript.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="resources/slow.js"></script> +<script> + +async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList) { + var entries = entryList.getEntries(); + assert_equals(entries.length, 1, + "Exactly one entry is expected."); + var longtask = entries[0]; + assert_equals(longtask.entryType, "longtask", + "entryType expected to be: longtask"); + assert_equals(longtask.name, "same-origin-self", + "name expected to be: same-origin-self"); + assert_greater_than(longtask.duration, 50, + "duration expected to be greater than 50ms threshold"); + assert_equals(longtask.startTime, Math.floor(longtask.startTime), + "startTime expected to have 1 miillisecond granularity"); + + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + "Exactly one attribution entry is expected"); + var attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, "taskattribution"); + assert_equals(attribution.name, "frame"); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + + observer.disconnect(); + t.done(); + }) + ); + observer.observe({entryTypes: ["longtask"]}); + +}, "Performance longtask entries are observable"); + +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-raf.html b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-raf.html new file mode 100644 index 0000000..7edb8451 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/longtask-raf.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="resources/slowraf.js"></script> +<script> + +async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList) { + var entries = entryList.getEntries(); + assert_equals(entries.length, 1, + "Exactly one entry is expected."); + var longtask = entries[0]; + assert_equals(longtask.entryType, "longtask", + "entryType expected to be: longtask"); + assert_equals(longtask.name, "same-origin-self", + "name expected to be: same-origin-self"); + assert_greater_than(longtask.duration, 50, + "duration expected to be greater than 50ms threshold"); + assert_equals(longtask.startTime, Math.floor(longtask.startTime), + "startTime expected to have 1 miillisecond granularity"); + + // Assert the TaskAttributionTiming entry in attribution. + assert_equals(longtask.attribution.length, 1, + "Exactly one attribution entry is expected"); + var attribution = longtask.attribution[0]; + assert_equals(attribution.entryType, "taskattribution"); + assert_equals(attribution.name, "frame"); + assert_equals(attribution.duration, 0); + assert_equals(attribution.startTime, 0); + + observer.disconnect(); + t.done(); + }) + ); + observer.observe({entryTypes: ["longtask"]}); + +}, "Performance longtask entries are observable"); + +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slow.js b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slow.js new file mode 100644 index 0000000..302b216 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slow.js
@@ -0,0 +1,4 @@ + +/* Generate a slow task */ +var begin = window.performance.now(); +while (window.performance.now() < begin + 51);
diff --git a/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slowraf.js b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slowraf.js new file mode 100644 index 0000000..8103bc6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/performance-timing/longtask/resources/slowraf.js
@@ -0,0 +1,6 @@ + +window.requestAnimationFrame(function() { + /* Generate a slow task */ + var begin = window.performance.now(); + while (window.performance.now() < begin + 51); +});
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index e33469d..4bc15ac 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -344,6 +344,12 @@ method readAsBinaryString method readAsDataURL method readAsText +interface Float32ImageData + getter colorSpace + getter data + getter height + getter width + method constructor interface ForeignFetchEvent : ExtendableEvent getter origin getter request @@ -510,9 +516,12 @@ method close method constructor interface ImageData + getter colorSpace + getter data getter height getter width method constructor + method createImageData interface InstallEvent : ExtendableEvent method constructor method registerForeignFetch
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt index 170fd3c..60010f18 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1314,6 +1314,10 @@ setter unicodeRange setter variant setter weight +interface FontFaceSetLoadEvent : Event + attribute @@toStringTag + getter fontfaces + method constructor interface FormData attribute @@toStringTag method @@iterator @@ -3017,6 +3021,8 @@ method transferFromImageBitmap interface ImageData attribute @@toStringTag + getter colorSpace + getter data getter height getter width method constructor
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt index 170fd3c..60010f18 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1314,6 +1314,10 @@ setter unicodeRange setter variant setter weight +interface FontFaceSetLoadEvent : Event + attribute @@toStringTag + getter fontfaces + method constructor interface FormData attribute @@toStringTag method @@iterator @@ -3017,6 +3021,8 @@ method transferFromImageBitmap interface ImageData attribute @@toStringTag + getter colorSpace + getter data getter height getter width method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 4ba23236..9c93825 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -345,6 +345,12 @@ method readAsBinaryString method readAsDataURL method readAsText +interface Float32ImageData + getter colorSpace + getter data + getter height + getter width + method constructor interface ForeignFetchEvent : ExtendableEvent getter origin getter request @@ -511,9 +517,12 @@ method close method constructor interface ImageData + getter colorSpace + getter data getter height getter width method constructor + method createImageData interface InstallEvent : ExtendableEvent method constructor method registerForeignFetch
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 2452562e..179caa5 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -368,6 +368,8 @@ method close method constructor interface ImageData + getter colorSpace + getter data getter height getter width method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 02dde09..d859f5d 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -387,6 +387,8 @@ [Worker] method constructor [Worker] interface ImageData [Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data [Worker] getter height [Worker] getter width [Worker] method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt index dd40740..89fed15 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1385,6 +1385,10 @@ setter unicodeRange setter variant setter weight +interface FontFaceSetLoadEvent : Event + attribute @@toStringTag + getter fontfaces + method constructor interface FormData attribute @@toStringTag method @@iterator @@ -3088,6 +3092,8 @@ method transferFromImageBitmap interface ImageData attribute @@toStringTag + getter colorSpace + getter data getter height getter width method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index ebb785d..c644e8f 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -382,6 +382,8 @@ [Worker] method constructor [Worker] interface ImageData [Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data [Worker] getter height [Worker] getter width [Worker] method constructor
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 69ddde5..0e953d1 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -354,6 +354,13 @@ [Worker] method readAsBinaryString [Worker] method readAsDataURL [Worker] method readAsText +[Worker] interface Float32ImageData +[Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data +[Worker] getter height +[Worker] getter width +[Worker] method constructor [Worker] interface FormData [Worker] attribute @@toStringTag [Worker] method @@iterator @@ -534,9 +541,12 @@ [Worker] method constructor [Worker] interface ImageData [Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data [Worker] getter height [Worker] getter width [Worker] method constructor +[Worker] method createImageData [Worker] interface MessageChannel [Worker] attribute @@toStringTag [Worker] getter port1
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 6260f407..8243e85 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1856,6 +1856,13 @@ setter onloadend setter onloadstart setter onprogress +interface Float32ImageData + attribute @@toStringTag + getter colorSpace + getter data + getter height + getter width + method constructor interface FocusEvent : UIEvent attribute @@toStringTag getter relatedTarget @@ -1880,6 +1887,10 @@ setter unicodeRange setter variant setter weight +interface FontFaceSetLoadEvent : Event + attribute @@toStringTag + getter fontfaces + method constructor interface FormData attribute @@toStringTag method @@iterator @@ -3676,9 +3687,12 @@ method takePhoto interface ImageData attribute @@toStringTag + getter colorSpace + getter data getter height getter width method constructor + method createImageData interface InputDeviceCapabilities attribute @@toStringTag getter firesTouchEvents
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt index fc7acef4..087a14e 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -349,6 +349,13 @@ [Worker] method readAsBinaryString [Worker] method readAsDataURL [Worker] method readAsText +[Worker] interface Float32ImageData +[Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data +[Worker] getter height +[Worker] getter width +[Worker] method constructor [Worker] interface FormData [Worker] attribute @@toStringTag [Worker] method @@iterator @@ -529,9 +536,12 @@ [Worker] method constructor [Worker] interface ImageData [Worker] attribute @@toStringTag +[Worker] getter colorSpace +[Worker] getter data [Worker] getter height [Worker] getter width [Worker] method constructor +[Worker] method createImageData [Worker] interface MessageChannel [Worker] attribute @@toStringTag [Worker] getter port1
diff --git a/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp b/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp index 95e4dc3b..6b28b52d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp
@@ -45,6 +45,13 @@ V8Window::installLongTaskObserver(isolate, world, instanceObject, prototypeObject, interfaceObject); } + } else if (wrapperTypeInfo == &V8Document::wrapperTypeInfo) { + if (RuntimeEnabledFeatures::setRootScrollerEnabled() || + (originTrialContext && + originTrialContext->isTrialEnabled("RootScroller"))) { + V8Document::installRootScroller(isolate, world, v8::Local<v8::Object>(), + prototypeObject, interfaceObject); + } } }
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py new file mode 100644 index 0000000..a4b7416 --- /dev/null +++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -0,0 +1,233 @@ +# Copyright (c) 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Generic generator for configuration files in JSON5 format. + +The configuration file is expected to contain either a data array or a data map, +an optional parameters validation map, and an optional metdata map. Examples: +{ + data: [ + "simple_item", + "simple_item2", + {name:"complex_item", param:"Hello World"}, + ], +} + +{ + metadata: { + namespace: "css", + }, + parameters: { + param1: {default: 1, valid_values:[1,2,3]}, + param2: {valid_type: "str"}, + }, + data: { + "simple_item": {}, + "item": {param1:1, param2: "Hello World"}, + "bad_item_fails_validation": { + name: "bad_item_fails_validation", + param1: "bad_value_fails_valid_values_check", + param2: 1.9, + unknown_param_fails_validation: true, + }, + }, +} + +The entries in data array/map are stored in the array self.name_dictionaries. +Each entry in name_dictionaries is always stored as a dictionary. +A simple non-map item is converted to a dictionary containing one entry with +key of "name" and its value the simple item. + +The order of entries in name_dictionaries is the same as that specified in the +data array. While for the data map case, by default the entries are sorted +alphabetically by name. + +The optional map "parameters" specifies the default values and the valid values +or valid types contained in the data entries. If parameters is specified, then +data entries may not contain keys not present in parameters. + +The optional map "metadata" overrides the values specified in default_metadata +if present, and stored as self.metadata. Keys in "metadata" must be present in +default_metadata or an exception raised. +""" + +import argparse +import ast +import copy +import os +import os.path +import re + + +def _json5_load(lines): + # Use json5.loads when json5 is available. Currently we use simple + # regexs to convert well-formed JSON5 to PYL format. + # Strip away comments and quote unquoted keys. + re_comment = re.compile(r"^\s*//.*$|//+ .*$", re.MULTILINE) + re_map_keys = re.compile(r"^\s+([$A-Za-z_][\w]*)\s*:", re.MULTILINE) + pyl = re.sub(re_map_keys, r"'\1':", re.sub(re_comment, "", lines)) + # Convert map values of true/false to Python version True/False. + re_true = re.compile(r":\s*true\b") + re_false = re.compile(r":\s*false\b") + pyl = re.sub(re_true, ":True", re.sub(re_false, ":False", pyl)) + return ast.literal_eval(pyl) + + +def _merge_doc(doc, doc2): + def _merge_dict(key): + if key in doc or key in doc2: + merged = doc.get(key, {}) + merged.update(doc2.get(key, {})) + doc[key] = merged + + _merge_dict("metadata") + _merge_dict("parameters") + if type(doc["data"]) is list: + doc["data"].extend(doc2["data"]) + else: + _merge_dict("data") + + +class Json5File(object): + def __init__(self, doc, default_metadata=None): + self.name_dictionaries = [] + self.metadata = copy.deepcopy(default_metadata if default_metadata else {}) + self._defaults = {} + self._process(doc) + + @classmethod + def load_from_files(cls, file_paths, default_metadata): + merged_doc = dict() + for path in file_paths: + assert path.endswith(".json5") + with open(os.path.abspath(path)) as json5_file: + doc = _json5_load(json5_file.read()) + if not merged_doc: + merged_doc = doc + else: + _merge_doc(merged_doc, doc) + return Json5File(merged_doc, default_metadata) + + def _process(self, doc): + # Process optional metadata map entries. + for key, value in doc.get("metadata", {}).items(): + self._process_metadata(key, value) + # Get optional parameters map, and get the default value map from it. + parameters = doc.get("parameters", {}) + if parameters: + self._get_defaults(parameters) + # Process normal entries. + items = doc["data"] + if type(items) is list: + for item in items: + entry = self._get_entry(item, parameters) + self.name_dictionaries.append(entry) + else: + for key, value in items.items(): + value["name"] = key + entry = self._get_entry(value, parameters) + self.name_dictionaries.append(entry) + self.name_dictionaries.sort(key=lambda entry: entry["name"]) + + def _process_metadata(self, key, value): + if key not in self.metadata: + raise Exception("Unknown metadata: '%s'\nKnown metadata: %s" % + (key, self.metadata.keys())) + self.metadata[key] = value + + def _get_defaults(self, parameters): + for key, value in parameters.items(): + if value and "default" in value: + self._defaults[key] = value["default"] + else: + self._defaults[key] = None + + def _get_entry(self, item, parameters): + entry = copy.deepcopy(self._defaults) + if type(item) is not dict: + entry["name"] = item + return entry + if "name" not in item: + raise Exception("Missing name in item: %s" % item) + entry["name"] = item.pop("name") + for key, value in item.items(): + if key not in parameters: + raise Exception( + "Unknown parameter: '%s'\nKnown params: %s" % + (key, parameters.keys())) + if parameters[key]: + self._validate_parameter(parameters[key], value) + entry[key] = value + return entry + + def _validate_parameter(self, parameter, value): + valid_values = parameter.get("valid_values") + if valid_values and value not in valid_values: + raise Exception("Unknown value: '%s'\nKnown values: %s" % + (value, valid_values)) + valid_type = parameter.get("valid_type") + if valid_type and type(value).__name__ != valid_type: + raise Exception("Incorrect type: '%s'\nExpected type: %s" % + (type(value).__name__, valid_type)) + + +class Writer(object): + # Subclasses should override. + class_name = None + default_metadata = None + + def __init__(self, json5_files): + self._outputs = {} # file_name -> generator + self.gperf_path = None + if isinstance(json5_files, basestring): + json5_files = [json5_files] + if json5_files: + self.json5_file = Json5File.load_from_files(json5_files, + self.default_metadata) + + def _write_file_if_changed(self, output_dir, contents, file_name): + path = os.path.join(output_dir, file_name) + + # The build system should ensure our output directory exists, but just + # in case. + directory = os.path.dirname(path) + if not os.path.exists(directory): + os.makedirs(directory) + + # Only write the file if the contents have changed. This allows ninja to + # skip rebuilding targets which depend on the output. + with open(path, "a+") as output_file: + output_file.seek(0) + if output_file.read() != contents: + output_file.truncate(0) + output_file.write(contents) + + def write_files(self, output_dir): + for file_name, generator in self._outputs.items(): + self._write_file_if_changed(output_dir, generator(), file_name) + + def set_gperf_path(self, gperf_path): + self.gperf_path = gperf_path + + +class Maker(object): + def __init__(self, writer_class): + self._writer_class = writer_class + + def main(self): + parser = argparse.ArgumentParser() + # Require at least one input file. + parser.add_argument("files", nargs="+") + + parser.add_argument("--gperf", default="gperf") + parser.add_argument("--developer_dir", help="Path to Xcode.") + parser.add_argument("--output_dir", default=os.getcwd()) + args = parser.parse_args() + + if args.developer_dir: + os.environ["DEVELOPER_DIR"] = args.developer_dir + + writer = self._writer_class(args.files) + writer.set_gperf_path(args.gperf) + writer.write_files(args.output_dir)
diff --git a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py index 99041b2..f86922f7 100755 --- a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py +++ b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
@@ -5,10 +5,9 @@ import subprocess import sys -from in_file import InFile from name_utilities import enum_for_css_keyword from name_utilities import upper_first_letter -import in_generator +import json5_generator import license @@ -106,19 +105,16 @@ """ -class CSSValueKeywordsWriter(in_generator.Writer): +class CSSValueKeywordsWriter(json5_generator.Writer): class_name = "CSSValueKeywords" - defaults = { - 'mode': None, - } def __init__(self, file_paths): - in_generator.Writer.__init__(self, file_paths) + json5_generator.Writer.__init__(self, file_paths) self._outputs = {(self.class_name + ".h"): self.generate_header, (self.class_name + ".cpp"): self.generate_implementation, } - self._value_keywords = self.in_file.name_dictionaries + self._value_keywords = self.json5_file.name_dictionaries first_keyword_id = 1 for offset, keyword in enumerate(self._value_keywords): keyword['lower_name'] = keyword['name'].lower() @@ -174,4 +170,4 @@ if __name__ == "__main__": - in_generator.Maker(CSSValueKeywordsWriter).main(sys.argv) + json5_generator.Maker(CSSValueKeywordsWriter).main()
diff --git a/third_party/WebKit/Source/build/scripts/make_internal_settings.py b/third_party/WebKit/Source/build/scripts/make_internal_settings.py index abaef7b8..0838614 100755 --- a/third_party/WebKit/Source/build/scripts/make_internal_settings.py +++ b/third_party/WebKit/Source/build/scripts/make_internal_settings.py
@@ -29,29 +29,23 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys -import in_generator +import json5_generator import template_expander import name_utilities from make_settings import to_passing_type, to_idl_type -class MakeInternalSettingsWriter(in_generator.Writer): - defaults = { - 'type': 'bool', - 'initial': None, - 'invalidate': None, - } - default_parameters = {} +class MakeInternalSettingsWriter(json5_generator.Writer): filters = { 'upper_first': name_utilities.upper_first, 'to_passing_type': to_passing_type, 'to_idl_type': to_idl_type, } - def __init__(self, in_file_path): - super(MakeInternalSettingsWriter, self).__init__(in_file_path) + def __init__(self, json5_file_path): + super(MakeInternalSettingsWriter, self).__init__(json5_file_path) - self.in_file.name_dictionaries.sort(key=lambda entry: entry['name']) + self.json5_file.name_dictionaries.sort(key=lambda entry: entry['name']) self._outputs = { ('InternalSettingsGenerated.h'): self.generate_header, @@ -59,7 +53,7 @@ ('InternalSettingsGenerated.idl'): self.generate_idl, } self._template_context = { - 'settings': self.in_file.name_dictionaries, + 'settings': self.json5_file.name_dictionaries, } @template_expander.use_jinja('InternalSettingsGenerated.h.tmpl', filters=filters) @@ -76,4 +70,4 @@ if __name__ == '__main__': - in_generator.Maker(MakeInternalSettingsWriter).main(sys.argv) + json5_generator.Maker(MakeInternalSettingsWriter).main()
diff --git a/third_party/WebKit/Source/build/scripts/make_settings.py b/third_party/WebKit/Source/build/scripts/make_settings.py index f1436ca..431863a 100755 --- a/third_party/WebKit/Source/build/scripts/make_settings.py +++ b/third_party/WebKit/Source/build/scripts/make_settings.py
@@ -29,9 +29,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys -import in_generator -import template_expander + +import json5_generator import name_utilities +import template_expander def to_passing_type(typename): @@ -54,29 +55,24 @@ return None -class MakeSettingsWriter(in_generator.Writer): - defaults = { - 'type': 'bool', - 'initial': None, - 'invalidate': None, - } - default_parameters = {} +class MakeSettingsWriter(json5_generator.Writer): filters = { + 'cpp_bool': name_utilities.cpp_bool, 'upper_first': name_utilities.upper_first, 'to_passing_type': to_passing_type, 'to_idl_type': to_idl_type, } - def __init__(self, in_file_path): - super(MakeSettingsWriter, self).__init__(in_file_path) + def __init__(self, json5_file_path): + super(MakeSettingsWriter, self).__init__(json5_file_path) - self.in_file.name_dictionaries.sort(key=lambda entry: entry['name']) + self.json5_file.name_dictionaries.sort(key=lambda entry: entry['name']) self._outputs = { ('SettingsMacros.h'): self.generate_macros, } self._template_context = { - 'settings': self.in_file.name_dictionaries, + 'settings': self.json5_file.name_dictionaries, } @template_expander.use_jinja('SettingsMacros.h.tmpl', filters=filters) @@ -85,4 +81,4 @@ if __name__ == '__main__': - in_generator.Maker(MakeSettingsWriter).main(sys.argv) + json5_generator.Maker(MakeSettingsWriter).main()
diff --git a/third_party/WebKit/Source/build/scripts/name_utilities.py b/third_party/WebKit/Source/build/scripts/name_utilities.py index 90b80ba..c5fdcaa 100644 --- a/third_party/WebKit/Source/build/scripts/name_utilities.py +++ b/third_party/WebKit/Source/build/scripts/name_utilities.py
@@ -93,6 +93,16 @@ return os.path.basename(entry['name']) +def cpp_bool(value): + if value is True: + return 'true' + if value is False: + return 'false' + # Return value as is, which for example may be a platform-dependent constant + # such as "defaultSelectTrailingWhitespaceEnabled". + return value + + def cpp_name(entry): return entry['ImplementedAs'] or script_name(entry)
diff --git a/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl index 60677760..c21f1b6 100644 --- a/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl
@@ -22,11 +22,11 @@ // End of SETTINGS_MEMBER_VARIABLES. #define SETTINGS_INITIALIZER_LIST \ - {% for setting in settings if setting.initial and setting.type != 'bool' %} + {% for setting in settings if setting.initial is not none and setting.type != 'bool' %} , m_{{setting.name}}({{setting.initial}}) \ {% endfor %} - {% for setting in settings if setting.initial and setting.type == 'bool' %} - , m_{{setting.name}}({{setting.initial}}) \ + {% for setting in settings if setting.initial is not none and setting.type == 'bool' %} + , m_{{setting.name}}({{setting.initial|cpp_bool}}) \ {% endfor %} // End of SETTINGS_INITIALIZER_LIST.
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index b6e498519..c6f4436 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -342,14 +342,14 @@ inputs = scripts_for_in_files + [ "../build/scripts/make_settings.py", "../build/scripts/templates/SettingsMacros.h.tmpl", - "frame/Settings.in", + "frame/Settings.json5", ] outputs = [ "$blink_core_output_dir/SettingsMacros.h", ] args = [ - rebase_path("frame/Settings.in", root_build_dir), + rebase_path("frame/Settings.json5", root_build_dir), "--output_dir", rel_blink_core_gen_dir, ] @@ -363,7 +363,7 @@ "../build/scripts/templates/InternalSettingsGenerated.idl.tmpl", "../build/scripts/templates/InternalSettingsGenerated.cpp.tmpl", "../build/scripts/templates/InternalSettingsGenerated.h.tmpl", - "frame/Settings.in", + "frame/Settings.json5", ] outputs = [ "$blink_core_output_dir/testing/InternalSettingsGenerated.idl", @@ -372,7 +372,7 @@ ] args = [ - rebase_path("frame/Settings.in", root_build_dir), + rebase_path("frame/Settings.json5", root_build_dir), "--output_dir", "$rel_blink_core_gen_dir/testing", ] @@ -494,8 +494,8 @@ script = "../build/scripts/make_css_value_keywords.py" in_files = [ - "css/CSSValueKeywords.in", - "css/SVGCSSValueKeywords.in", + "css/CSSValueKeywords.json5", + "css/SVGCSSValueKeywords.json5", ] outputs = [ "$blink_core_output_dir/CSSValueKeywords.cpp",
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp index e6bfdee..b015454e6 100644 --- a/third_party/WebKit/Source/core/animation/Animation.cpp +++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -1080,7 +1080,6 @@ } void Animation::pauseForTesting(double pauseTime) { - RELEASE_ASSERT(!paused()); setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand); if (hasActiveAnimationsOnCompositor()) toKeyframeEffectReadOnly(m_content.get())
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni index e2ee147..eb7930c 100644 --- a/third_party/WebKit/Source/core/core_idl_files.gni +++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -192,6 +192,7 @@ "frame/ImageBitmap.idl", "frame/Location.idl", "frame/VisualViewport.idl", + "html/Float32ImageData.idl", "html/FormData.idl", "html/HTMLAllCollection.idl", "html/HTMLAnchorElement.idl",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn index 023484e0..7000b35e 100644 --- a/third_party/WebKit/Source/core/css/BUILD.gn +++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -356,12 +356,19 @@ "properties/CSSPropertyAPIPaintOrder.cpp", "properties/CSSPropertyAPIRotate.cpp", "properties/CSSPropertyAPIScrollSnapCoordinate.cpp", + "properties/CSSPropertyAPIShapeMargin.cpp", "properties/CSSPropertyAPISize.cpp", + "properties/CSSPropertyAPIStrokeDasharray.cpp", + "properties/CSSPropertyAPITabSize.cpp", "properties/CSSPropertyAPITextDecorationColor.cpp", "properties/CSSPropertyAPITextDecorationSkip.cpp", + "properties/CSSPropertyAPITextIndent.cpp", "properties/CSSPropertyAPITextUnderlinePosition.cpp", "properties/CSSPropertyAPITransformOrigin.cpp", "properties/CSSPropertyAPITranslate.cpp", + "properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp", + "properties/CSSPropertyAPIWebkitHighlight.cpp", + "properties/CSSPropertyAPIWebkitLineClamp.cpp", "properties/CSSPropertyAPIWebkitPadding.cpp", "properties/CSSPropertyAPIWebkitTransformOriginZ.cpp", "properties/CSSPropertyAPIWillChange.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in index 68f3635..27001cd 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.in +++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -355,7 +355,7 @@ scroll-snap-destination runtime_flag=CSSScrollSnapPoints, converter=convertPosition scroll-snap-coordinate runtime_flag=CSSScrollSnapPoints, converter=convertSnapCoordinates, api_class shape-image-threshold interpolable, type_name=float -shape-margin interpolable, converter=convertLength +shape-margin interpolable, converter=convertLength, api_class shape-outside interpolable, converter=convertShapeValue, typedom_types=[Image] shape-rendering inherited, svg size custom_all, api_class @@ -364,7 +364,7 @@ stop-color interpolable, svg, converter=convertColor stop-opacity interpolable, svg, converter=convertNumberOrPercentage stroke interpolable, inherited, svg, setter=setStrokePaint, custom_all -stroke-dasharray interpolable, inherited, svg, name_for_methods=StrokeDashArray, converter=convertStrokeDasharray +stroke-dasharray interpolable, inherited, svg, name_for_methods=StrokeDashArray, converter=convertStrokeDasharray, api_class stroke-dashoffset interpolable, inherited, svg, name_for_methods=StrokeDashOffset, converter=convertLength stroke-linecap svg, inherited, type_name=LineCap, name_for_methods=CapStyle stroke-linejoin svg, inherited, type_name=LineJoin, name_for_methods=JoinStyle @@ -372,8 +372,8 @@ stroke-opacity interpolable, inherited, svg, converter=convertNumberOrPercentage stroke-width interpolable, inherited, svg, converter=convertUnzoomedLength table-layout -tab-size inherited, converter=convertLengthOrTabSpaces, type_name=TabSize -text-align inherited, custom_value, keyword_only, keywords=[left|right|center|justify|-webkit-left|-webkit-right|-webkit-center|start|end], initial_keyword=start +tab-size inherited, converter=convertLengthOrTabSpaces, type_name=TabSize, api_class +text-align inherited, custom_value, keyword_only, keywords=[left|right|center|justify|webkitLeft|webkitRight|webkitCenter|start|end], initial_keyword=start text-align-last inherited, type_name=TextAlignLast text-anchor inherited, svg text-combine-upright inherited, type_name=TextCombine, name_for_methods=TextCombine @@ -383,7 +383,7 @@ text-decoration-line runtime_flag=CSS3TextDecorations, name_for_methods=TextDecoration, type_name=TextDecoration, converter=convertFlags<TextDecoration> text-decoration-skip runtime_flag=CSS3TextDecorations, inherited, type_name=TextDecorationSkip, converter=convertFlags<TextDecorationSkip>, api_class text-decoration-style runtime_flag=CSS3TextDecorations, type_name=TextDecorationStyle -text-indent interpolable, inherited, custom_all +text-indent interpolable, inherited, custom_all, api_class text-justify runtime_flag=CSS3Text, inherited, type_name=TextJustify text-overflow type_name=TextOverflow text-shadow interpolable, inherited, converter=convertShadowList @@ -415,7 +415,7 @@ -webkit-box-decoration-break -webkit-box-direction inherited, independent, keyword_only, keywords=[normal|reverse], initial_keyword=normal -webkit-box-flex type_name=float --webkit-box-flex-group type_name=unsigned int +-webkit-box-flex-group type_name=unsigned int, api_class -webkit-box-lines -webkit-box-ordinal-group type_name=unsigned int -webkit-box-orient @@ -428,10 +428,10 @@ column-rule-width interpolable, converter=convertLineWidth<unsigned short> column-span type_name=ColumnSpan column-width interpolable, converter=convertComputedLength<float>, custom_all --webkit-highlight inherited, converter=convertString<CSSValueNone> +-webkit-highlight inherited, converter=convertString<CSSValueNone>, api_class -webkit-hyphenate-character inherited, name_for_methods=HyphenationString, converter=convertString<CSSValueAuto> -webkit-line-break inherited, type_name=LineBreak --webkit-line-clamp type_name=LineClampValue +-webkit-line-clamp type_name=LineClampValue, api_class -webkit-margin-after-collapse type_name=EMarginCollapse -webkit-margin-before-collapse type_name=EMarginCollapse -webkit-margin-bottom-collapse type_name=EMarginCollapse, name_for_methods=MarginAfterCollapse
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp index 4dc999a..71eedf7 100644 --- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp +++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
@@ -8,7 +8,6 @@ #include "core/css/CSSURIValue.h" #include "core/css/CSSValueList.h" #include "core/css/CSSVariableReferenceValue.h" -#include "core/css/parser/CSSParserContext.h" #include "core/css/parser/CSSParserIdioms.h" #include "core/css/parser/CSSPropertyParserHelpers.h" #include "core/css/parser/CSSVariableParser.h" @@ -130,7 +129,8 @@ } const CSSValue* consumeSingleType(const CSSSyntaxComponent& syntax, - CSSParserTokenRange& range) { + CSSParserTokenRange& range, + const CSSParserContext* context) { using namespace CSSPropertyParserHelpers; switch (syntax.m_type) { @@ -153,9 +153,7 @@ case CSSSyntaxType::Color: return consumeColor(range, HTMLStandardMode); case CSSSyntaxType::Image: - // TODO(timloh): This probably needs a proper parser context for relative - // URL resolution. - return consumeImage(range, strictCSSParserContext()); + return consumeImage(range, context); case CSSSyntaxType::Url: return consumeUrl(range); case CSSSyntaxType::Integer: @@ -177,25 +175,27 @@ } const CSSValue* consumeSyntaxComponent(const CSSSyntaxComponent& syntax, - CSSParserTokenRange range) { + CSSParserTokenRange range, + const CSSParserContext* context) { // CSS-wide keywords are already handled by the CSSPropertyParser if (syntax.m_repeatable) { CSSValueList* list = CSSValueList::createSpaceSeparated(); while (!range.atEnd()) { - const CSSValue* value = consumeSingleType(syntax, range); + const CSSValue* value = consumeSingleType(syntax, range, context); if (!value) return nullptr; list->append(*value); } return list; } - const CSSValue* result = consumeSingleType(syntax, range); + const CSSValue* result = consumeSingleType(syntax, range, context); if (!range.atEnd()) return nullptr; return result; } const CSSValue* CSSSyntaxDescriptor::parse(CSSParserTokenRange range, + const CSSParserContext* context, bool isAnimationTainted) const { if (isTokenStream()) { return CSSVariableParser::parseRegisteredPropertyValue(range, false, @@ -203,7 +203,8 @@ } range.consumeWhitespace(); for (const CSSSyntaxComponent& component : m_syntaxComponents) { - if (const CSSValue* result = consumeSyntaxComponent(component, range)) + if (const CSSValue* result = + consumeSyntaxComponent(component, range, context)) return result; } return CSSVariableParser::parseRegisteredPropertyValue(range, true,
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h index 63e9e14d..0ff8908 100644 --- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h +++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h
@@ -9,6 +9,7 @@ namespace blink { +class CSSParserContext; class CSSValue; enum class CSSSyntaxType { @@ -42,7 +43,9 @@ public: CSSSyntaxDescriptor(String syntax); - const CSSValue* parse(CSSParserTokenRange, bool isAnimationTainted) const; + const CSSValue* parse(CSSParserTokenRange, + const CSSParserContext*, + bool isAnimationTainted) const; bool isValid() const { return !m_syntaxComponents.isEmpty(); } bool isTokenStream() const { return m_syntaxComponents.size() == 1 &&
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.in b/third_party/WebKit/Source/core/css/CSSValueKeywords.in deleted file mode 100644 index 1cebf6a..0000000 --- a/third_party/WebKit/Source/core/css/CSSValueKeywords.in +++ /dev/null
@@ -1,1113 +0,0 @@ -// -// CSS value names -// - -// The mode argument is used to limit the keyword to be used only for certain -// CSSParserModes. Values that have the prefix -internal- are only allowed by -// CSSParserModes listed in allowInternalPropertyAndValue() - -inherit -initial -// -// outline-style -// border-top-style -// border-bottom-style -// border-left-style -// border-right-style -// The order here must match the order of the EBorderStyle enum in ComputedStyleConstants.h. -none -hidden -inset -groove -outset -ridge -dotted -dashed -solid -double - -// -// font -// -caption -icon -menu -message-box -small-caption --webkit-mini-control --webkit-small-control --webkit-control -status-bar - -// -// font-style -// -//normal -italic -oblique -// The following is only allowed in @font-face: -all - -// font-variant-ligatures: -// -// normal -common-ligatures -no-common-ligatures -discretionary-ligatures -no-discretionary-ligatures -historical-ligatures -no-historical-ligatures -contextual -no-contextual - -// font-variant-caps: -// -// normal -small-caps -all-small-caps -petite-caps -all-petite-caps -unicase -titling-caps - -// font-variant-numeric -// normal -lining-nums -oldstyle-nums -proportional-nums -tabular-nums -diagonal-fractions -stacked-fractions -ordinal -slashed-zero - -// -// font-weigth -// -normal -bold -bolder -lighter -100 -200 -300 -400 -500 -600 -700 -800 -900 - -// -// font-stretch -// -ultra-condensed -extra-condensed -condensed -semi-condensed -semi-expanded -expanded -extra-expanded -ultra-expanded - -// -// font-size -// -xx-small -x-small -small -medium -large -x-large -xx-large --webkit-xxx-large -smaller -larger - -// -// font-family (<generic-family> in CSS 2.1) -// -serif -sans-serif -cursive -fantasy -monospace --webkit-body --webkit-pictograph - -// -// font-display -// -//auto -//block -swap -fallback -optional - -// -// -// *-color -// -aqua -black -blue -fuchsia -gray -green -lime -maroon -navy -olive -orange -purple -red -silver -teal -white -yellow -transparent --webkit-link --webkit-activelink -activeborder -activecaption -appworkspace -background -buttonface -buttonhighlight -buttonshadow -buttontext -captiontext -graytext -highlight -highlighttext -inactiveborder -inactivecaption -inactivecaptiontext -infobackground -infotext -menutext -scrollbar -threeddarkshadow -threedface -threedhighlight -threedlightshadow -threedshadow -window -windowframe -windowtext --internal-active-list-box-selection --internal-active-list-box-selection-text --internal-inactive-list-box-selection --internal-inactive-list-box-selection-text --webkit-focus-ring-color mode=QuirksOrUASheet -currentcolor -grey -// -// Value used to implement the behavior in: -// https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk --internal-quirk-inherit -// -// background-repeat -// -repeat -repeat-x -repeat-y -no-repeat -// round -// space -// -// -webkit-mask-composite -// -clear -copy -source-over -source-in -source-out -source-atop -destination-over -destination-in -destination-out -destination-atop -xor -// highlight -plus-lighter -// -// vertical-align -// -baseline -middle -sub -super -text-top -text-bottom -top -bottom -// HTML alignment MIDDLE has no corresponding CSS alignment --webkit-baseline-middle -// -// text-align -// The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). -// --webkit-auto -left -right -center -justify --webkit-left --webkit-right --webkit-center --webkit-match-parent --internal-center -// -// text-justify -// -//auto -//none -inter-word -distribute -// -// list-style-position -// -outside -inside -// -// list-style-type -// The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). -// -disc -circle -square -decimal -decimal-leading-zero -arabic-indic -bengali -cambodian -khmer -devanagari -gujarati -gurmukhi -kannada -lao -malayalam -mongolian -myanmar -oriya -persian -urdu -telugu -tibetan -thai -lower-roman -upper-roman -lower-greek -lower-alpha -lower-latin -upper-alpha -upper-latin -cjk-earthly-branch -cjk-heavenly-stem -ethiopic-halehame -ethiopic-halehame-am -ethiopic-halehame-ti-er -ethiopic-halehame-ti-et -hangul -hangul-consonant -korean-hangul-formal -korean-hanja-formal -korean-hanja-informal -hebrew -armenian -lower-armenian -upper-armenian -georgian -cjk-ideographic -simp-chinese-formal -simp-chinese-informal -trad-chinese-formal -trad-chinese-informal -hiragana -katakana -hiragana-iroha -katakana-iroha -//none -// -// display -// The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). -// -inline -block -list-item -inline-block -table -inline-table -table-row-group -table-header-group -table-footer-group -table-row -table-column-group -table-column -table-cell -table-caption --webkit-box --webkit-inline-box -flex -inline-flex -grid -inline-grid -contents -//none --webkit-flex --webkit-inline-flex -// -// cursor -// The order of this enum must match the order found in CSSPropertyParser::consumeCursor(). -// -auto -crosshair -default -pointer -move -vertical-text -cell -context-menu -alias -// copy -progress -no-drop -not-allowed -zoom-in -zoom-out -e-resize -ne-resize -nw-resize -n-resize -se-resize -sw-resize -s-resize -w-resize -ew-resize -ns-resize -nesw-resize -nwse-resize -col-resize -row-resize -text -wait -help -all-scroll --webkit-grab --webkit-grabbing --webkit-zoom-in --webkit-zoom-out -// none -// -// direction -// -ltr -rtl -// -// text-transform -// -capitalize -uppercase -lowercase -//none -// -// visibility -// -visible -//hidden -collapse -// -// Unordered rest -// -a3 -a4 -a5 -above -absolute -always -avoid -b4 -b5 -below -bidi-override -blink -both -close-quote -embed -fixed -hand -hide -isolate -isolate-override -plaintext --webkit-isolate --webkit-isolate-override --webkit-plaintext -landscape -ledger -legal -letter -line-through -local -no-close-quote -no-open-quote -nowrap -open-quote -overlay -overline -portrait -pre -pre-line -pre-wrap -relative -scroll -separate -show -static -thick -thin -underline -wavy --webkit-nowrap - -// CSS3 Values -// box-align -stretch -start -end -//center -//baseline - -// box-decoration-break -clone -slice - -// box-direction -// normal -reverse - -// box-orient -horizontal -vertical -inline-axis -block-axis - -// box-pack -// start -// end -// center -// justify - -// box-lines -single -multiple - -// align-content -// start -// end -flex-start -flex-end -// center -space-between -space-around -space-evenly -// stretch -unsafe -safe - -// align-items / align-self -// flex-start -// flex-end -// center -// baseline -// stretch - -// justify-content -// start -// end -// flex-start -// flex-end -// center -// space-between -// space-around -// space-evenly -// stretch -// unsafe -// safe - - -// flex-flow -row -row-reverse -column -column-reverse -// nowrap -wrap -wrap-reverse - -// grid-auto-flow -auto-flow -dense - -// -// -webkit-user-modify -// -read-only -read-write -read-write-plaintext-only - -// -// -webkit-user-drag -// -element - -// -// CSS3 intrinsic dimension keywords -// --webkit-min-content --webkit-max-content --webkit-fill-available --webkit-fit-content -min-content -max-content -fit-content - -// -// text-overflow -// -clip -ellipsis - -// -// text-decoration-skip -// -objects -ink - -// -// -webkit-margin-collapse -// -// collapse -// separate -discard - -// -// word-break -// -break-all -keep-all - -// -// word-wrap -// -break-word - -// -// nbsp-mode -// -space - -// -// -webkit-line-break -// -// auto -loose -// normal -strict -after-white-space - -// hyphens -manual - -// -webkit-appearance -// The order here must match the order in the ControlPart enum in ThemeTypes.h. -// All appearance values that should be accepted by the parser should be listed between 'checkbox' and 'textarea': -checkbox -radio -push-button -square-button -button -button-bevel -inner-spin-button -listbox -listitem -media-enter-fullscreen-button -media-exit-fullscreen-button -media-fullscreen-volume-slider -media-fullscreen-volume-slider-thumb -media-mute-button -media-play-button -media-overlay-play-button -media-toggle-closed-captions-button -media-slider -media-sliderthumb -media-volume-slider-container -media-volume-slider -media-volume-sliderthumb -media-controls-background -media-controls-fullscreen-background -media-current-time-display -media-time-remaining-display --internal-media-cast-off-button --internal-media-overlay-cast-off-button --internal-media-track-selection-checkmark --internal-media-closed-captions-icon --internal-media-subtitles-icon --internal-media-overflow-button --internal-media-download-button -menulist -menulist-button -menulist-text -menulist-textfield -meter -progress-bar -progress-bar-value -slider-horizontal -slider-vertical -sliderthumb-horizontal -sliderthumb-vertical -caret -searchfield -searchfield-cancel-button -textfield -textarea -// An appearance value that should not be accepted by the parser: -caps-lock-indicator - -// -// border-image -// -// stretch -// repeat -round - -// -// background-clip/background-origin -// -// border/content/padding are deprecated and ultimately will only apply to the -webkit- form of these properties. -// border-box/content-box/padding-box should be used instead. -// -border -border-box -content -content-box -padding -padding-box - -// CSS 3 SHAPES -margin-box - -// -// background-size -// -contain -cover - -// -// -webkit-rtl-ordering -// -logical -visual - -// -// animation-direction -// -alternate -alternate-reverse - -// -// animation-fill-mode -// -forwards -backwards -// both - -// -// animation-iteration-count -infinite - -// -// animation-play-state -// -running -paused - -// -// transform-style -// -flat -preserve-3d - -// -// transition-timing-function -// animation-timing-function -// -ease -linear -ease-in -ease-out -ease-in-out -step-start -step-middle -step-end -steps -cubic-bezier - -// -// zoom -// -document -reset - -// -// user-zoom -// -// fixed -zoom - -// -// pointer-events -// -visiblePainted -visibleFill -visibleStroke -//visible -painted -fill -stroke -bounding-box -//all -//none - -// -// speech -// -spell-out -digits -literal-punctuation -no-punctuation - -// -// -webkit-font-smoothing -// -// auto -// none -antialiased -subpixel-antialiased - -// text-rendering -//auto -optimizeSpeed -optimizeLegibility -geometricPrecision - -// -webkit-color-adjust -economy -exact - -// -webkit-writing-mode -// SVG compatibility -lr -rl -tb -lr-tb -rl-tb -tb-rl -// Standard values from CSS3 -horizontal-tb -vertical-rl -vertical-lr - -// -webkit-ruby-position -after -before - -// -webkit-text-emphasis-position -over -under - -// -webkit-text-emphasis-style -filled -open -dot -// circle -double-circle -triangle -sesame - -// -webkit-radial-gradient -// circle -ellipse -closest-side -closest-corner -farthest-side -farthest-corner -// contain -// cover - -// text-orientation/-webkit-text-orientation -mixed -sideways -sideways-right -upright -vertical-right - -// -webkit-font-feature-settings -on -off - -// image-rendering -//auto -//optimizeSpeed -optimizeQuality -pixelated --webkit-optimize-contrast - -// shape-outside -nonzero -evenodd -at -// closest-side -// farthest-side - -alphabetic - -// (display-mode:) media feature -fullscreen -standalone -minimal-ui -browser - -// position -sticky - -// (pointer:) media feature -// none -coarse -fine - -// (hover:) media feature -// none -on-demand -hover - -// blend modes -// normal -multiply -screen -// overlay -darken -lighten -color-dodge -color-burn -hard-light -soft-light -difference -exclusion -hue -saturation -color -luminosity - -// object-fit -scale-down - -// column-fill -balance - -// overflow --webkit-paged-x --webkit-paged-y - -// -webkit-app-region -drag -no-drag - -// grid-{column|row}-{start|end} -span - -// grid-template-{columns|rows} -minmax - -// text-indent -each-line -//hanging // hanging exists in SVGCSSValueKeywords.in - -// (scan:) media feature -progressive -interlace - -// -// paint-order -// -// normal -// fill -// stroke -markers - -// -// CSS3 viewport-length keywords -// --internal-extend-to-zoom - -// isolation -// auto -isolate - -// touch-action -pan-x -pan-y -pan-left -pan-right -pan-up -pan-down -manipulation -pinch-zoom - -// justify-items / justify-self -// auto -// stretch -// baseline -last-baseline -// center -// start -// end -self-start -self-end -// flex-start -// flex-end -// left -// right -// unsafe -// safe -legacy - -// scroll-behavior -// auto -smooth - -// will-change -// auto -contents -scroll-position - -// all -// initial -// inherit -revert -unset - -// background-image, etc. -linear-gradient -radial-gradient -repeating-linear-gradient -repeating-radial-gradient -paint --webkit-cross-fade --webkit-gradient --webkit-linear-gradient --webkit-radial-gradient --webkit-repeating-linear-gradient --webkit-repeating-radial-gradient --webkit-image-set - -// deprecated gradients -from -to -color-stop -radial - -// content -attr -counter -counters - -// clip -rect - -// shapes -polygon - -// @font-face src -format - -// (-webkit-)filter -invert -grayscale -sepia -saturate -hue-rotate -opacity -brightness -contrast -blur -drop-shadow -url - -// colors -rgb -rgba -hsl -hsla - -// transform -matrix -matrix3d -perspective -rotate -rotateX -rotateY -rotateZ -rotate3d -scale -scaleX -scaleY -scaleZ -scale3d -skew -skewX -skewY -translate -translateX -translateY -translateZ -translate3d - -// motion path -path - -calc --webkit-calc - -// scroll-snap-type -// none -mandatory -proximity -from-image - -// containment -paint -style -layout -size - -// grid auto-repeat -auto-fill -auto-fit - -var --internal-variable-value - -// break-before, break-after, break-inside -avoid-page -page -recto -verso -avoid-column - -// shape -// rect -// round -
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 new file mode 100644 index 0000000..6dc8b5a --- /dev/null +++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
@@ -0,0 +1,1125 @@ +{ +// The mode argument is used to limit the keyword to be used only for certain +// CSSParserModes. Values that have the prefix -internal- are only allowed by +// CSSParserModes listed in allowInternalPropertyAndValue() + +parameters: { + mode: {}, +}, + +// +// CSS value names +// + +data: [ + + "inherit", + "initial", + // + // outline-style + // border-top-style + // border-bottom-style + // border-left-style + // border-right-style + // The order here must match the order of the EBorderStyle enum in ComputedStyleConstants.h. + "none", + "hidden", + "inset", + "groove", + "outset", + "ridge", + "dotted", + "dashed", + "solid", + "double", + + // + // font + // + "caption", + "icon", + "menu", + "message-box", + "small-caption", + "-webkit-mini-control", + "-webkit-small-control", + "-webkit-control", + "status-bar", + + // + // font-style + // + //normal + "italic", + "oblique", + // The following is only allowed in @font-face: + "all", + + // font-variant-ligatures: + // + // normal + "common-ligatures", + "no-common-ligatures", + "discretionary-ligatures", + "no-discretionary-ligatures", + "historical-ligatures", + "no-historical-ligatures", + "contextual", + "no-contextual", + + // font-variant-caps: + // + // normal + "small-caps", + "all-small-caps", + "petite-caps", + "all-petite-caps", + "unicase", + "titling-caps", + + // font-variant-numeric + // normal + "lining-nums", + "oldstyle-nums", + "proportional-nums", + "tabular-nums", + "diagonal-fractions", + "stacked-fractions", + "ordinal", + "slashed-zero", + + // + // font-weigth + // + "normal", + "bold", + "bolder", + "lighter", + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + + // + // font-stretch + // + "ultra-condensed", + "extra-condensed", + "condensed", + "semi-condensed", + "semi-expanded", + "expanded", + "extra-expanded", + "ultra-expanded", + + // + // font-size + // + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "-webkit-xxx-large", + "smaller", + "larger", + + // + // font-family (<generic-family> in CSS 2.1) + // + "serif", + "sans-serif", + "cursive", + "fantasy", + "monospace", + "-webkit-body", + "-webkit-pictograph", + + // + // font-display + // + //auto + //block + "swap", + "fallback", + "optional", + + // + // + // *-color + // + "aqua", + "black", + "blue", + "fuchsia", + "gray", + "green", + "lime", + "maroon", + "navy", + "olive", + "orange", + "purple", + "red", + "silver", + "teal", + "white", + "yellow", + "transparent", + "-webkit-link", + "-webkit-activelink", + "activeborder", + "activecaption", + "appworkspace", + "background", + "buttonface", + "buttonhighlight", + "buttonshadow", + "buttontext", + "captiontext", + "graytext", + "highlight", + "highlighttext", + "inactiveborder", + "inactivecaption", + "inactivecaptiontext", + "infobackground", + "infotext", + "menutext", + "scrollbar", + "threeddarkshadow", + "threedface", + "threedhighlight", + "threedlightshadow", + "threedshadow", + "window", + "windowframe", + "windowtext", + "-internal-active-list-box-selection", + "-internal-active-list-box-selection-text", + "-internal-inactive-list-box-selection", + "-internal-inactive-list-box-selection-text", + { + name: "-webkit-focus-ring-color", + mode: "QuirksOrUASheet", + }, + "currentcolor", + "grey", + // + // Value used to implement the behavior in: + // https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk + "-internal-quirk-inherit", + // + // background-repeat + // + "repeat", + "repeat-x", + "repeat-y", + "no-repeat", + // round + // space + // + // -webkit-mask-composite + // + "clear", + "copy", + "source-over", + "source-in", + "source-out", + "source-atop", + "destination-over", + "destination-in", + "destination-out", + "destination-atop", + "xor", + // highlight + "plus-lighter", + // + // vertical-align + // + "baseline", + "middle", + "sub", + "super", + "text-top", + "text-bottom", + "top", + "bottom", + // HTML alignment MIDDLE has no corresponding CSS alignment + "-webkit-baseline-middle", + // + // text-align + // The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). + // + "-webkit-auto", + "left", + "right", + "center", + "justify", + "-webkit-left", + "-webkit-right", + "-webkit-center", + "-webkit-match-parent", + "-internal-center", + // + // text-justify + // + //auto + //none + "inter-word", + "distribute", + // + // list-style-position + // + "outside", + "inside", + // + // list-style-type + // The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). + // + "disc", + "circle", + "square", + "decimal", + "decimal-leading-zero", + "arabic-indic", + "bengali", + "cambodian", + "khmer", + "devanagari", + "gujarati", + "gurmukhi", + "kannada", + "lao", + "malayalam", + "mongolian", + "myanmar", + "oriya", + "persian", + "urdu", + "telugu", + "tibetan", + "thai", + "lower-roman", + "upper-roman", + "lower-greek", + "lower-alpha", + "lower-latin", + "upper-alpha", + "upper-latin", + "cjk-earthly-branch", + "cjk-heavenly-stem", + "ethiopic-halehame", + "ethiopic-halehame-am", + "ethiopic-halehame-ti-er", + "ethiopic-halehame-ti-et", + "hangul", + "hangul-consonant", + "korean-hangul-formal", + "korean-hanja-formal", + "korean-hanja-informal", + "hebrew", + "armenian", + "lower-armenian", + "upper-armenian", + "georgian", + "cjk-ideographic", + "simp-chinese-formal", + "simp-chinese-informal", + "trad-chinese-formal", + "trad-chinese-informal", + "hiragana", + "katakana", + "hiragana-iroha", + "katakana-iroha", + //none + // + // display + // The order of this enum must match the order found in CSSParserFastPaths::isValidKeywordPropertyAndValue(). + // + "inline", + "block", + "list-item", + "inline-block", + "table", + "inline-table", + "table-row-group", + "table-header-group", + "table-footer-group", + "table-row", + "table-column-group", + "table-column", + "table-cell", + "table-caption", + "-webkit-box", + "-webkit-inline-box", + "flex", + "inline-flex", + "grid", + "inline-grid", + "contents", + //none + "-webkit-flex", + "-webkit-inline-flex", + // + // cursor + // The order of this enum must match the order found in CSSPropertyParser::consumeCursor(). + // + "auto", + "crosshair", + "default", + "pointer", + "move", + "vertical-text", + "cell", + "context-menu", + "alias", + // copy + "progress", + "no-drop", + "not-allowed", + "zoom-in", + "zoom-out", + "e-resize", + "ne-resize", + "nw-resize", + "n-resize", + "se-resize", + "sw-resize", + "s-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "text", + "wait", + "help", + "all-scroll", + "-webkit-grab", + "-webkit-grabbing", + "-webkit-zoom-in", + "-webkit-zoom-out", + // none + // + // direction + // + "ltr", + "rtl", + // + // text-transform + // + "capitalize", + "uppercase", + "lowercase", + //none + // + // visibility + // + "visible", + //hidden + "collapse", + // + // Unordered rest + // + "a3", + "a4", + "a5", + "above", + "absolute", + "always", + "avoid", + "b4", + "b5", + "below", + "bidi-override", + "blink", + "both", + "close-quote", + "embed", + "fixed", + "hand", + "hide", + "isolate", + "isolate-override", + "plaintext", + "-webkit-isolate", + "-webkit-isolate-override", + "-webkit-plaintext", + "landscape", + "ledger", + "legal", + "letter", + "line-through", + "local", + "no-close-quote", + "no-open-quote", + "nowrap", + "open-quote", + "overlay", + "overline", + "portrait", + "pre", + "pre-line", + "pre-wrap", + "relative", + "scroll", + "separate", + "show", + "static", + "thick", + "thin", + "underline", + "wavy", + "-webkit-nowrap", + + // CSS3 Values + // box-align + "stretch", + "start", + "end", + //center + //baseline + + // box-decoration-break + "clone", + "slice", + + // box-direction + // normal + "reverse", + + // box-orient + "horizontal", + "vertical", + "inline-axis", + "block-axis", + + // box-pack + // start + // end + // center + // justify + + // box-lines + "single", + "multiple", + + // align-content + // start + // end + "flex-start", + "flex-end", + // center + "space-between", + "space-around", + "space-evenly", + // stretch + "unsafe", + "safe", + + // align-items / align-self + // flex-start + // flex-end + // center + // baseline + // stretch + + // justify-content + // start + // end + // flex-start + // flex-end + // center + // space-between + // space-around + // space-evenly + // stretch + // unsafe + // safe + + + // flex-flow + "row", + "row-reverse", + "column", + "column-reverse", + // nowrap + "wrap", + "wrap-reverse", + + // grid-auto-flow + "auto-flow", + "dense", + + // + // -webkit-user-modify + // + "read-only", + "read-write", + "read-write-plaintext-only", + + // + // -webkit-user-drag + // + "element", + + // + // CSS3 intrinsic dimension keywords + // + "-webkit-min-content", + "-webkit-max-content", + "-webkit-fill-available", + "-webkit-fit-content", + "min-content", + "max-content", + "fit-content", + + // + // text-overflow + // + "clip", + "ellipsis", + + // + // text-decoration-skip + // + "objects", + "ink", + + // + // -webkit-margin-collapse + // + // collapse + // separate + "discard", + + // + // word-break + // + "break-all", + "keep-all", + + // + // word-wrap + // + "break-word", + + // + // nbsp-mode + // + "space", + + // + // -webkit-line-break + // + // auto + "loose", + // normal + "strict", + "after-white-space", + + // hyphens + "manual", + + // -webkit-appearance + // The order here must match the order in the ControlPart enum in ThemeTypes.h. + // All appearance values that should be accepted by the parser should be listed between 'checkbox' and 'textarea': + "checkbox", + "radio", + "push-button", + "square-button", + "button", + "button-bevel", + "inner-spin-button", + "listbox", + "listitem", + "media-enter-fullscreen-button", + "media-exit-fullscreen-button", + "media-fullscreen-volume-slider", + "media-fullscreen-volume-slider-thumb", + "media-mute-button", + "media-play-button", + "media-overlay-play-button", + "media-toggle-closed-captions-button", + "media-slider", + "media-sliderthumb", + "media-volume-slider-container", + "media-volume-slider", + "media-volume-sliderthumb", + "media-controls-background", + "media-controls-fullscreen-background", + "media-current-time-display", + "media-time-remaining-display", + "-internal-media-cast-off-button", + "-internal-media-overlay-cast-off-button", + "-internal-media-track-selection-checkmark", + "-internal-media-closed-captions-icon", + "-internal-media-subtitles-icon", + "-internal-media-overflow-button", + "-internal-media-download-button", + "menulist", + "menulist-button", + "menulist-text", + "menulist-textfield", + "meter", + "progress-bar", + "progress-bar-value", + "slider-horizontal", + "slider-vertical", + "sliderthumb-horizontal", + "sliderthumb-vertical", + "caret", + "searchfield", + "searchfield-cancel-button", + "textfield", + "textarea", + // An appearance value that should not be accepted by the parser: + "caps-lock-indicator", + + // + // border-image + // + // stretch + // repeat + "round", + + // + // background-clip/background-origin + // + // border/content/padding are deprecated and ultimately will only apply to the -webkit- form of these properties. + // border-box/content-box/padding-box should be used instead. + // + "border", + "border-box", + "content", + "content-box", + "padding", + "padding-box", + + // CSS 3 SHAPES + "margin-box", + + // + // background-size + // + "contain", + "cover", + + // + // -webkit-rtl-ordering + // + "logical", + "visual", + + // + // animation-direction + // + "alternate", + "alternate-reverse", + + // + // animation-fill-mode + // + "forwards", + "backwards", + // both + + // + // animation-iteration-count + "infinite", + + // + // animation-play-state + // + "running", + "paused", + + // + // transform-style + // + "flat", + "preserve-3d", + + // + // transition-timing-function + // animation-timing-function + // + "ease", + "linear", + "ease-in", + "ease-out", + "ease-in-out", + "step-start", + "step-middle", + "step-end", + "steps", + "cubic-bezier", + + // + // zoom + // + "document", + "reset", + + // + // user-zoom + // + // fixed + "zoom", + + // + // pointer-events + // + "visiblePainted", + "visibleFill", + "visibleStroke", + //visible + "painted", + "fill", + "stroke", + "bounding-box", + //all + //none + + // + // speech + // + "spell-out", + "digits", + "literal-punctuation", + "no-punctuation", + + // + // -webkit-font-smoothing + // + // auto + // none + "antialiased", + "subpixel-antialiased", + + // text-rendering + //auto + "optimizeSpeed", + "optimizeLegibility", + "geometricPrecision", + + // -webkit-color-adjust + "economy", + "exact", + + // -webkit-writing-mode + // SVG compatibility + "lr", + "rl", + "tb", + "lr-tb", + "rl-tb", + "tb-rl", + // Standard values from CSS3 + "horizontal-tb", + "vertical-rl", + "vertical-lr", + + // -webkit-ruby-position + "after", + "before", + + // -webkit-text-emphasis-position + "over", + "under", + + // -webkit-text-emphasis-style + "filled", + "open", + "dot", + // circle + "double-circle", + "triangle", + "sesame", + + // -webkit-radial-gradient + // circle + "ellipse", + "closest-side", + "closest-corner", + "farthest-side", + "farthest-corner", + // contain + // cover + + // text-orientation/-webkit-text-orientation + "mixed", + "sideways", + "sideways-right", + "upright", + "vertical-right", + + // -webkit-font-feature-settings + "on", + "off", + + // image-rendering + //auto + //optimizeSpeed + "optimizeQuality", + "pixelated", + "-webkit-optimize-contrast", + + // shape-outside + "nonzero", + "evenodd", + "at", + // closest-side + // farthest-side + + "alphabetic", + + // (display-mode:) media feature + "fullscreen", + "standalone", + "minimal-ui", + "browser", + + // position + "sticky", + + // (pointer:) media feature + // none + "coarse", + "fine", + + // (hover:) media feature + // none + "on-demand", + "hover", + + // blend modes + // normal + "multiply", + "screen", + // overlay + "darken", + "lighten", + "color-dodge", + "color-burn", + "hard-light", + "soft-light", + "difference", + "exclusion", + "hue", + "saturation", + "color", + "luminosity", + + // object-fit + "scale-down", + + // column-fill + "balance", + + // overflow + "-webkit-paged-x", + "-webkit-paged-y", + + // -webkit-app-region + "drag", + "no-drag", + + // grid-{column|row}-{start|end} + "span", + + // grid-template-{columns|rows} + "minmax", + + // text-indent + "each-line", + //hanging // hanging exists in SVGCSSValueKeywords.in + + // (scan:) media feature + "progressive", + "interlace", + + // + // paint-order + // + // normal + // fill + // stroke + "markers", + + // + // CSS3 viewport-length keywords + // + "-internal-extend-to-zoom", + + // isolation + // auto + // isolate + + // touch-action + "pan-x", + "pan-y", + "pan-left", + "pan-right", + "pan-up", + "pan-down", + "manipulation", + "pinch-zoom", + + // justify-items / justify-self + // auto + // stretch + // baseline + "last-baseline", + // center + // start + // end + "self-start", + "self-end", + // flex-start + // flex-end + // left + // right + // unsafe + // safe + "legacy", + + // scroll-behavior + // auto + "smooth", + + // will-change + // auto + // contents + "scroll-position", + + // all + // initial + // inherit + "revert", + "unset", + + // background-image, etc. + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "paint", + "-webkit-cross-fade", + "-webkit-gradient", + "-webkit-linear-gradient", + "-webkit-radial-gradient", + "-webkit-repeating-linear-gradient", + "-webkit-repeating-radial-gradient", + "-webkit-image-set", + + // deprecated gradients + "from", + "to", + "color-stop", + "radial", + + // content + "attr", + "counter", + "counters", + + // clip + "rect", + + // shapes + "polygon", + + // @font-face src + "format", + + // (-webkit-)filter + "invert", + "grayscale", + "sepia", + "saturate", + "hue-rotate", + "opacity", + "brightness", + "contrast", + "blur", + "drop-shadow", + "url", + + // colors + "rgb", + "rgba", + "hsl", + "hsla", + + // transform + "matrix", + "matrix3d", + "perspective", + "rotate", + "rotateX", + "rotateY", + "rotateZ", + "rotate3d", + "scale", + "scaleX", + "scaleY", + "scaleZ", + "scale3d", + "skew", + "skewX", + "skewY", + "translate", + "translateX", + "translateY", + "translateZ", + "translate3d", + + // motion path + "path", + + "calc", + "-webkit-calc", + + // scroll-snap-type + // none + "mandatory", + "proximity", + "from-image", + + // containment + // paint + "style", + "layout", + "size", + + // grid auto-repeat + "auto-fill", + "auto-fit", + + "var", + "-internal-variable-value", + + // break-before, break-after, break-inside + "avoid-page", + "page", + "recto", + "verso", + "avoid-column", + + // shape + // rect + // round + +] +}
diff --git a/third_party/WebKit/Source/core/css/CSSVariableData.cpp b/third_party/WebKit/Source/core/css/CSSVariableData.cpp index 07b022425..58f2fa5 100644 --- a/third_party/WebKit/Source/core/css/CSSVariableData.cpp +++ b/third_party/WebKit/Source/core/css/CSSVariableData.cpp
@@ -73,7 +73,10 @@ const CSSValue* CSSVariableData::parseForSyntax( const CSSSyntaxDescriptor& syntax) const { DCHECK(!needsVariableResolution()); - return syntax.parse(tokenRange(), m_isAnimationTainted); + // TODO(timloh): This probably needs a proper parser context for + // relative URL resolution. + return syntax.parse(tokenRange(), strictCSSParserContext(), + m_isAnimationTainted); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetLoadEvent.idl b/third_party/WebKit/Source/core/css/FontFaceSetLoadEvent.idl index 201f53c2..047b12d 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSetLoadEvent.idl +++ b/third_party/WebKit/Source/core/css/FontFaceSetLoadEvent.idl
@@ -30,10 +30,10 @@ // https://dev.w3.org/csswg/css-font-loading/#fontfacesetloadevent -// TODO(foolip): This interface should have a constructor and -// [Exposed=Window,Worker], and thus not [NoInterfaceObject]. [ - NoInterfaceObject, + Constructor(DOMString type, optional FontFaceSetLoadEventInit eventInitDict), + // TODO(lunalu): Exposed=(Window,Worker) + Exposed=Window ] interface FontFaceSetLoadEvent : Event { - readonly attribute sequence<FontFace> fontfaces; + [SameObject] readonly attribute FrozenArray<FontFace> fontfaces; };
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp index 09683e1..71bbc5d70 100644 --- a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp +++ b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp
@@ -5,11 +5,14 @@ #include "core/css/PropertyRegistration.h" #include "core/animation/CSSValueInterpolationType.h" +#include "core/css/CSSStyleSheet.h" #include "core/css/CSSSyntaxDescriptor.h" #include "core/css/CSSValueList.h" #include "core/css/CSSVariableReferenceValue.h" #include "core/css/PropertyDescriptor.h" #include "core/css/PropertyRegistry.h" +#include "core/css/StyleSheetContents.h" +#include "core/css/parser/CSSParserContext.h" #include "core/css/parser/CSSTokenizer.h" #include "core/css/parser/CSSVariableParser.h" #include "core/css/resolver/StyleBuilderConverter.h" @@ -108,8 +111,10 @@ if (descriptor.hasInitialValue()) { CSSTokenizer tokenizer(descriptor.initialValue()); bool isAnimationTainted = false; - const CSSValue* initial = - syntaxDescriptor.parse(tokenizer.tokenRange(), isAnimationTainted); + const CSSValue* initial = syntaxDescriptor.parse( + tokenizer.tokenRange(), + document->elementSheet().contents()->parserContext(), + isAnimationTainted); if (!initial) { exceptionState.throwDOMException( SyntaxError,
diff --git a/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.in b/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.in deleted file mode 100644 index 139c7ced..0000000 --- a/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.in +++ /dev/null
@@ -1,282 +0,0 @@ -// -// SVG CSS value names -// - -// CSS_PROP_*_COLOR -// -aliceblue -antiquewhite -// aqua -aquamarine -azure -beige -bisque -// black -blanchedalmond -// blue -blueviolet -brown -burlywood -cadetblue -chartreuse -chocolate -coral -cornflowerblue -cornsilk -crimson -cyan -darkblue -darkcyan -darkgoldenrod -darkgray -darkgreen -darkgrey -darkkhaki -darkmagenta -darkolivegreen -darkorange -darkorchid -darkred -darksalmon -darkseagreen -darkslateblue -darkslategray -darkslategrey -darkturquoise -darkviolet -deeppink -deepskyblue -dimgray -dimgrey -dodgerblue -firebrick -floralwhite -forestgreen -// fuchsia -gainsboro -ghostwhite -gold -goldenrod -// gray -// grey -// green -greenyellow -honeydew -hotpink -indianred -indigo -ivory -khaki -lavender -lavenderblush -lawngreen -lemonchiffon -lightblue -lightcoral -lightcyan -lightgoldenrodyellow -lightgray -lightgreen -lightgrey -lightpink -lightsalmon -lightseagreen -lightskyblue -lightslategray -lightslategrey -lightsteelblue -lightyellow -// lime -limegreen -linen -magenta -// maroon -mediumaquamarine -mediumblue -mediumorchid -mediumpurple -mediumseagreen -mediumslateblue -mediumspringgreen -mediumturquoise -mediumvioletred -midnightblue -mintcream -mistyrose -moccasin -navajowhite -// navy -oldlace -// olive -olivedrab -// orange -orangered -orchid -palegoldenrod -palegreen -paleturquoise -palevioletred -papayawhip -peachpuff -peru -pink -plum -powderblue -// purple -rebeccapurple -// red -rosybrown -royalblue -saddlebrown -salmon -sandybrown -seagreen -seashell -sienna -// silver -skyblue -slateblue -slategray -slategrey -snow -springgreen -steelblue -tan -// teal -thistle -tomato -turquoise -violet -wheat -// white -whitesmoke -// yellow -yellowgreen - -// mask-type / mask-mode -alpha -luminance - -// CSS_PROP_CLIP_PATH -// CSS_PROP_CLIP_RULE -// nonzero and evenodd part of core CSS values now. - -// CSS_PROP_MASK -// CSS_PROP_OPACITY -accumulate -new - -// CSS_PROP_FILTER -// CSS_PROP_FLOOD_COLOR -//currentColor - -// CSS_PROP_FLOOD_OPACITY -// CSS_PROP_LIGHTING_COLOR -//currentColor - -// CSS_PROP_STOP_COLOR -// CSS_PROP_STOP_OPACITY -// CSS_PROP_COLOR_INTERPOLATION -//auto -sRGB -linearRGB - -// CSS_PROP_COLOR_INTERPOLATION_FILTERS -//auto -//sRGB -//linearRGB - -// CSS_PROP_COLOR_PROFILE -//sRGB - -// CSS_PROP_COLOR_RENDERING -//auto -//optimizeSpeed -//optimizeQuality - -//// CSS_PROP_FILL -//currentColor - -// CSS_PROP_FILL_OPACITY -// CSS_PROP_FILL_RULE -//nonzero -//evenodd - -// CSS_PROP_IMAGE_RENDERING -//auto -//optimizeSpeed -//optimizeQuality - -// CSS_PROP_MARKER -// CSS_PROP_MARKER_END -// CSS_PROP_MARKER_MID -// CSS_PROP_MARKER_START -// CSS_PROP_SHAPE_RENDERING -//auto -//optimizeSpeed -crispEdges -//geometricPrecision - -// CSS_PROP_STROKE -// CSS_PROP_STROKE_DASHARRAY -// CSS_PROP_STROKE_DASHOFFSET -// CSS_PROP_STROKE_LINECAP -butt -// round -// square - -// CSS_PROP_STROKE_LINEJOIN -miter -// round -bevel - -// CSS_PROP_STROKE_MITERLIMIT -// CSS_PROP_STROKE_OPACITY -// CSS_PROP_STROKE_WIDTH - -// CSS_PROP_ALIGNMENT_BASELINE -//auto -// baseline -before-edge -after-edge -//middle -central -text-before-edge -text-after-edge -ideographic -hanging -mathematical - -// CSS_PROP_BASELINE_SHIFT -//baseline -// sub -// super - -// CSS_PROP_DOMINANT_BASELINE -//auto -use-script -no-change -reset-size - -// CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL - -// CSS_PROP_GLYPH_ORIENTATION_VERTICAL -// CSS_PROP_TEXT_ANCHOR -// start -// middle -// end - -// CSS_PROP_BUFFERED_RENDERING -// auto -// static -dynamic - -// CSS_PROP_VECTOR_EFFECT -// none -non-scaling-stroke - -// CSS_PROP_PAINT_ORDER -// normal -// fill -// stroke -// markers
diff --git a/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.json5 b/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.json5 new file mode 100644 index 0000000..23811899 --- /dev/null +++ b/third_party/WebKit/Source/core/css/SVGCSSValueKeywords.json5
@@ -0,0 +1,286 @@ +{ +// +// SVG CSS value names +// + +data: [ + // CSS_PROP_*_COLOR + // + "aliceblue", + "antiquewhite", + // aqua + "aquamarine", + "azure", + "beige", + "bisque", + // black + "blanchedalmond", + // blue + "blueviolet", + "brown", + "burlywood", + "cadetblue", + "chartreuse", + "chocolate", + "coral", + "cornflowerblue", + "cornsilk", + "crimson", + "cyan", + "darkblue", + "darkcyan", + "darkgoldenrod", + "darkgray", + "darkgreen", + "darkgrey", + "darkkhaki", + "darkmagenta", + "darkolivegreen", + "darkorange", + "darkorchid", + "darkred", + "darksalmon", + "darkseagreen", + "darkslateblue", + "darkslategray", + "darkslategrey", + "darkturquoise", + "darkviolet", + "deeppink", + "deepskyblue", + "dimgray", + "dimgrey", + "dodgerblue", + "firebrick", + "floralwhite", + "forestgreen", + // fuchsia + "gainsboro", + "ghostwhite", + "gold", + "goldenrod", + // gray + // grey + // green + "greenyellow", + "honeydew", + "hotpink", + "indianred", + "indigo", + "ivory", + "khaki", + "lavender", + "lavenderblush", + "lawngreen", + "lemonchiffon", + "lightblue", + "lightcoral", + "lightcyan", + "lightgoldenrodyellow", + "lightgray", + "lightgreen", + "lightgrey", + "lightpink", + "lightsalmon", + "lightseagreen", + "lightskyblue", + "lightslategray", + "lightslategrey", + "lightsteelblue", + "lightyellow", + // lime + "limegreen", + "linen", + "magenta", + // maroon + "mediumaquamarine", + "mediumblue", + "mediumorchid", + "mediumpurple", + "mediumseagreen", + "mediumslateblue", + "mediumspringgreen", + "mediumturquoise", + "mediumvioletred", + "midnightblue", + "mintcream", + "mistyrose", + "moccasin", + "navajowhite", + // navy + "oldlace", + // olive + "olivedrab", + // orange + "orangered", + "orchid", + "palegoldenrod", + "palegreen", + "paleturquoise", + "palevioletred", + "papayawhip", + "peachpuff", + "peru", + "pink", + "plum", + "powderblue", + // purple + "rebeccapurple", + // red + "rosybrown", + "royalblue", + "saddlebrown", + "salmon", + "sandybrown", + "seagreen", + "seashell", + "sienna", + // silver + "skyblue", + "slateblue", + "slategray", + "slategrey", + "snow", + "springgreen", + "steelblue", + "tan", + // teal + "thistle", + "tomato", + "turquoise", + "violet", + "wheat", + // white + "whitesmoke", + // yellow + "yellowgreen", + + // mask-type / mask-mode + "alpha", + "luminance", + + // CSS_PROP_CLIP_PATH + // CSS_PROP_CLIP_RULE + // nonzero and evenodd part of core CSS values now. + + // CSS_PROP_MASK + // CSS_PROP_OPACITY + "accumulate", + "new", + + // CSS_PROP_FILTER + // CSS_PROP_FLOOD_COLOR + //currentColor + + // CSS_PROP_FLOOD_OPACITY + // CSS_PROP_LIGHTING_COLOR + //currentColor + + // CSS_PROP_STOP_COLOR + // CSS_PROP_STOP_OPACITY + // CSS_PROP_COLOR_INTERPOLATION + //auto + "sRGB", + "linearRGB", + + // CSS_PROP_COLOR_INTERPOLATION_FILTERS + //auto + //sRGB + //linearRGB + + // CSS_PROP_COLOR_PROFILE + //sRGB + + // CSS_PROP_COLOR_RENDERING + //auto + //optimizeSpeed + //optimizeQuality + + //// CSS_PROP_FILL + //currentColor + + // CSS_PROP_FILL_OPACITY + // CSS_PROP_FILL_RULE + //nonzero + //evenodd + + // CSS_PROP_IMAGE_RENDERING + //auto + //optimizeSpeed + //optimizeQuality + + // CSS_PROP_MARKER + // CSS_PROP_MARKER_END + // CSS_PROP_MARKER_MID + // CSS_PROP_MARKER_START + // CSS_PROP_SHAPE_RENDERING + //auto + //optimizeSpeed + "crispEdges", + //geometricPrecision + + // CSS_PROP_STROKE + // CSS_PROP_STROKE_DASHARRAY + // CSS_PROP_STROKE_DASHOFFSET + // CSS_PROP_STROKE_LINECAP + "butt", + // round + // square + + // CSS_PROP_STROKE_LINEJOIN + "miter", + // round + "bevel", + + // CSS_PROP_STROKE_MITERLIMIT + // CSS_PROP_STROKE_OPACITY + // CSS_PROP_STROKE_WIDTH + + // CSS_PROP_ALIGNMENT_BASELINE + //auto + // baseline + "before-edge", + "after-edge", + //middle + "central", + "text-before-edge", + "text-after-edge", + "ideographic", + "hanging", + "mathematical", + + // CSS_PROP_BASELINE_SHIFT + //baseline + // sub + // super + + // CSS_PROP_DOMINANT_BASELINE + //auto + "use-script", + "no-change", + "reset-size", + + // CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL + + // CSS_PROP_GLYPH_ORIENTATION_VERTICAL + // CSS_PROP_TEXT_ANCHOR + // start + // middle + // end + + // CSS_PROP_BUFFERED_RENDERING + // auto + // static + "dynamic", + + // CSS_PROP_VECTOR_EFFECT + // none + "non-scaling-stroke", + + // CSS_PROP_PAINT_ORDER + // normal + // fill + // stroke + // markers +] +}
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp index a7d9ba7..bf5c2567 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -89,7 +89,7 @@ // TODO(timloh): This is a bit wasteful, we parse the registered property // to validate but throw away the result. if (registration && - !registration->syntax().parse(tokenizer.tokenRange(), + !registration->syntax().parse(tokenizer.tokenRange(), context, isAnimationTainted)) { return MutableStylePropertySet::SetResult{didParse, didChange}; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index b7f9ff35..86ad465 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -344,12 +344,6 @@ return nullptr; } -static CSSValue* consumeWebkitHighlight(CSSParserTokenRange& range) { - if (range.peek().id() == CSSValueNone) - return consumeIdent(range); - return consumeString(range); -} - class FontVariantLigaturesParser { STACK_ALLOCATED(); @@ -613,14 +607,6 @@ UnitlessQuirk::Allow); } -static CSSValue* consumeTabSize(CSSParserTokenRange& range, - CSSParserMode cssParserMode) { - CSSPrimitiveValue* parsedValue = consumeInteger(range, 0); - if (parsedValue) - return parsedValue; - return consumeLength(range, cssParserMode, ValueRangeNonNegative); -} - static CSSValue* consumeTextSizeAdjust(CSSParserTokenRange& range, CSSParserMode cssParserMode) { if (range.peek().id() == CSSValueAuto) @@ -713,48 +699,6 @@ return list; } -static CSSValue* consumeTextIndent(CSSParserTokenRange& range, - CSSParserMode cssParserMode) { - // [ <length> | <percentage> ] && hanging? && each-line? - // Keywords only allowed when css3Text is enabled. - CSSValueList* list = CSSValueList::createSpaceSeparated(); - - bool hasLengthOrPercentage = false; - bool hasEachLine = false; - bool hasHanging = false; - - do { - if (!hasLengthOrPercentage) { - if (CSSValue* textIndent = consumeLengthOrPercent( - range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow)) { - list->append(*textIndent); - hasLengthOrPercentage = true; - continue; - } - } - - if (RuntimeEnabledFeatures::css3TextEnabled()) { - CSSValueID id = range.peek().id(); - if (!hasEachLine && id == CSSValueEachLine) { - list->append(*consumeIdent(range)); - hasEachLine = true; - continue; - } - if (!hasHanging && id == CSSValueHanging) { - list->append(*consumeIdent(range)); - hasHanging = true; - continue; - } - } - return nullptr; - } while (!range.atEnd()); - - if (!hasLengthOrPercentage) - return nullptr; - - return list; -} - static bool validWidthOrHeightKeyword(CSSValueID id, const CSSParserContext* context) { if (id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || @@ -815,41 +759,6 @@ return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless); } -static CSSValue* consumeClipComponent(CSSParserTokenRange& range, - CSSParserMode cssParserMode) { - if (range.peek().id() == CSSValueAuto) - return consumeIdent(range); - return consumeLength(range, cssParserMode, ValueRangeAll, - UnitlessQuirk::Allow); -} - -static CSSValue* consumeClip(CSSParserTokenRange& range, - CSSParserMode cssParserMode) { - if (range.peek().id() == CSSValueAuto) - return consumeIdent(range); - - if (range.peek().functionId() != CSSValueRect) - return nullptr; - - CSSParserTokenRange args = consumeFunction(range); - // rect(t, r, b, l) || rect(t r b l) - CSSValue* top = consumeClipComponent(args, cssParserMode); - if (!top) - return nullptr; - bool needsComma = consumeCommaIncludingWhitespace(args); - CSSValue* right = consumeClipComponent(args, cssParserMode); - if (!right || (needsComma && !consumeCommaIncludingWhitespace(args))) - return nullptr; - CSSValue* bottom = consumeClipComponent(args, cssParserMode); - if (!bottom || (needsComma && !consumeCommaIncludingWhitespace(args))) - return nullptr; - CSSValue* left = consumeClipComponent(args, cssParserMode); - if (!left || !args.atEnd()) - return nullptr; - return CSSQuadValue::create(top, right, bottom, left, - CSSQuadValue::SerializeAsRect); -} - static bool consumePan(CSSParserTokenRange& range, CSSValue*& panX, CSSValue*& panY, @@ -904,17 +813,6 @@ return list; } -static CSSPrimitiveValue* consumeLineClamp(CSSParserTokenRange& range) { - if (range.peek().type() != PercentageToken && - range.peek().type() != NumberToken) - return nullptr; - CSSPrimitiveValue* clampValue = consumePercent(range, ValueRangeNonNegative); - if (clampValue) - return clampValue; - // When specifying number of lines, don't allow 0 as a valid value. - return consumePositiveInteger(range); -} - static CSSValue* consumeLocale(CSSParserTokenRange& range) { if (range.peek().id() == CSSValueAuto) return consumeIdent(range); @@ -1746,22 +1644,6 @@ return consumeUrl(range); } -static CSSValue* consumeStrokeDasharray(CSSParserTokenRange& range) { - CSSValueID id = range.peek().id(); - if (id == CSSValueNone) - return consumeIdent(range); - - CSSValueList* dashes = CSSValueList::createCommaSeparated(); - do { - CSSPrimitiveValue* dash = - consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeNonNegative); - if (!dash || (consumeCommaIncludingWhitespace(range) && range.atEnd())) - return nullptr; - dashes->append(*dash); - } while (!range.atEnd()); - return dashes; -} - static CSSValue* consumeBaselineShift(CSSParserTokenRange& range) { CSSValueID id = range.peek().id(); if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper) @@ -3140,8 +3022,6 @@ switch (property) { case CSSPropertyQuotes: return consumeQuotes(m_range); - case CSSPropertyWebkitHighlight: - return consumeWebkitHighlight(m_range); case CSSPropertyFontVariantCaps: return consumeFontVariantCaps(m_range); case CSSPropertyFontVariantLigatures: @@ -3157,8 +3037,6 @@ case CSSPropertyLetterSpacing: case CSSPropertyWordSpacing: return consumeSpacing(m_range, m_context->mode()); - case CSSPropertyTabSize: - return consumeTabSize(m_range, m_context->mode()); case CSSPropertyTextSizeAdjust: return consumeTextSizeAdjust(m_range, m_context->mode()); case CSSPropertyFontSize: @@ -3176,8 +3054,6 @@ property == CSSPropertyCounterIncrement ? 1 : 0); case CSSPropertySnapHeight: return consumeSnapHeight(m_range, m_context->mode()); - case CSSPropertyTextIndent: - return consumeTextIndent(m_range, m_context->mode()); case CSSPropertyMaxWidth: case CSSPropertyMaxHeight: return consumeMaxWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow); @@ -3223,16 +3099,12 @@ return consumeLengthOrPercent(m_range, m_context->mode(), ValueRangeNonNegative, UnitlessQuirk::Allow); - case CSSPropertyClip: - return consumeClip(m_range, m_context->mode()); case CSSPropertyTouchAction: return consumeTouchAction(m_range); case CSSPropertyScrollSnapDestination: case CSSPropertyObjectPosition: case CSSPropertyPerspectiveOrigin: return consumePosition(m_range, m_context->mode(), UnitlessQuirk::Forbid); - case CSSPropertyWebkitLineClamp: - return consumeLineClamp(m_range); case CSSPropertyWebkitFontSizeDelta: return consumeLength(m_range, m_context->mode(), ValueRangeAll, UnitlessQuirk::Allow); @@ -3264,9 +3136,6 @@ case CSSPropertyGridRowGap: return consumeLengthOrPercent(m_range, m_context->mode(), ValueRangeNonNegative); - case CSSPropertyShapeMargin: - return consumeLengthOrPercent(m_range, m_context->mode(), - ValueRangeNonNegative); case CSSPropertyShapeImageThreshold: return consumeNumber(m_range, ValueRangeAll); case CSSPropertyWebkitBoxOrdinalGroup: @@ -3372,8 +3241,6 @@ case CSSPropertyFlexGrow: case CSSPropertyFlexShrink: return consumeNumber(m_range, ValueRangeNonNegative); - case CSSPropertyStrokeDasharray: - return consumeStrokeDasharray(m_range); case CSSPropertyColumnRuleWidth: return consumeColumnRuleWidth(m_range, m_context->mode()); case CSSPropertyStrokeOpacity: @@ -3419,8 +3286,6 @@ case CSSPropertyBorderBottomLeftRadius: case CSSPropertyBorderBottomRightRadius: return consumeBorderRadiusCorner(m_range, m_context->mode()); - case CSSPropertyWebkitBoxFlexGroup: - return consumeInteger(m_range, 0); case CSSPropertyOrder: return consumeInteger(m_range); case CSSPropertyVerticalAlign:
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp new file mode 100644 index 0000000..38448d1 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp
@@ -0,0 +1,19 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIShapeMargin.h" + +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIShapeMargin::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + return CSSPropertyParserHelpers::consumeLengthOrPercent( + range, context->mode(), ValueRangeNonNegative); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp new file mode 100644 index 0000000..ca27b4b1 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp
@@ -0,0 +1,32 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIStrokeDasharray.h" + +#include "core/css/CSSValueList.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIStrokeDasharray::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + CSSValueID id = range.peek().id(); + if (id == CSSValueNone) + return CSSPropertyParserHelpers::consumeIdent(range); + + CSSValueList* dashes = CSSValueList::createCommaSeparated(); + do { + CSSPrimitiveValue* dash = CSSPropertyParserHelpers::consumeLengthOrPercent( + range, SVGAttributeMode, ValueRangeNonNegative); + if (!dash || + (CSSPropertyParserHelpers::consumeCommaIncludingWhitespace(range) && + range.atEnd())) + return nullptr; + dashes->append(*dash); + } while (!range.atEnd()); + return dashes; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp new file mode 100644 index 0000000..884ede0 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp
@@ -0,0 +1,23 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPITabSize.h" + +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPITabSize::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + CSSPrimitiveValue* parsedValue = + CSSPropertyParserHelpers::consumeInteger(range, 0); + if (parsedValue) + return parsedValue; + return CSSPropertyParserHelpers::consumeLength(range, context->mode(), + ValueRangeNonNegative); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp new file mode 100644 index 0000000..2935c41 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp
@@ -0,0 +1,59 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPITextIndent.h" + +#include "core/css/CSSValueList.h" +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" +#include "platform/RuntimeEnabledFeatures.h" + +namespace blink { + +const CSSValue* CSSPropertyAPITextIndent::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + // [ <length> | <percentage> ] && hanging? && each-line? + // Keywords only allowed when css3Text is enabled. + CSSValueList* list = CSSValueList::createSpaceSeparated(); + + bool hasLengthOrPercentage = false; + bool hasEachLine = false; + bool hasHanging = false; + + do { + if (!hasLengthOrPercentage) { + if (CSSValue* textIndent = + CSSPropertyParserHelpers::consumeLengthOrPercent( + range, context->mode(), ValueRangeAll, + CSSPropertyParserHelpers::UnitlessQuirk::Allow)) { + list->append(*textIndent); + hasLengthOrPercentage = true; + continue; + } + } + + if (RuntimeEnabledFeatures::css3TextEnabled()) { + CSSValueID id = range.peek().id(); + if (!hasEachLine && id == CSSValueEachLine) { + list->append(*CSSPropertyParserHelpers::consumeIdent(range)); + hasEachLine = true; + continue; + } + if (!hasHanging && id == CSSValueHanging) { + list->append(*CSSPropertyParserHelpers::consumeIdent(range)); + hasHanging = true; + continue; + } + } + return nullptr; + } while (!range.atEnd()); + + if (!hasLengthOrPercentage) + return nullptr; + + return list; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp new file mode 100644 index 0000000..458b25f --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp
@@ -0,0 +1,17 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.h" + +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIWebkitBoxFlexGroup::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + return CSSPropertyParserHelpers::consumeInteger(range, 0); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp new file mode 100644 index 0000000..798e4ca1 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp
@@ -0,0 +1,20 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIWebkitHighlight.h" + +#include "core/css/CSSStringValue.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIWebkitHighlight::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + if (range.peek().id() == CSSValueNone) + return CSSPropertyParserHelpers::consumeIdent(range); + return CSSPropertyParserHelpers::consumeString(range); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp new file mode 100644 index 0000000..982854e4 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp
@@ -0,0 +1,25 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIWebkitLineClamp.h" + +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIWebkitLineClamp::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + if (range.peek().type() != PercentageToken && + range.peek().type() != NumberToken) + return nullptr; + CSSPrimitiveValue* clampValue = + CSSPropertyParserHelpers::consumePercent(range, ValueRangeNonNegative); + if (clampValue) + return clampValue; + // When specifying number of lines, don't allow 0 as a valid value. + return CSSPropertyParserHelpers::consumePositiveInteger(range); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/ElementResolveContext.cpp b/third_party/WebKit/Source/core/css/resolver/ElementResolveContext.cpp index f894395..aad1e53 100644 --- a/third_party/WebKit/Source/core/css/resolver/ElementResolveContext.cpp +++ b/third_party/WebKit/Source/core/css/resolver/ElementResolveContext.cpp
@@ -36,7 +36,7 @@ m_rootElementStyle(document.documentElement() ? document.documentElement()->computedStyle() : document.computedStyle()), - m_elementLinkState(NotInsideLink), + m_elementLinkState(EInsideLink::kNotInsideLink), m_distributedToInsertionPoint(false) {} ElementResolveContext::ElementResolveContext(Element& element)
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index d837619..cddb5ad 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -693,11 +693,11 @@ if (element->isLink()) { state.style()->setIsLink(true); EInsideLink linkState = state.elementLinkState(); - if (linkState != NotInsideLink) { + if (linkState != EInsideLink::kNotInsideLink) { bool forceVisited = InspectorInstrumentation::forcePseudoState( element, CSSSelector::PseudoVisited); if (forceVisited) - linkState = InsideVisitedLink; + linkState = EInsideLink::kInsideVisitedLink; } state.style()->setInsideLink(linkState); } @@ -1114,7 +1114,7 @@ if (state.animationUpdate().isEmpty()) return false; - if (state.style()->insideLink() != NotInsideLink) { + if (state.style()->insideLink() != EInsideLink::kNotInsideLink) { DCHECK(state.applyPropertyToRegularStyle()); state.setApplyPropertyToVisitedLinkStyle(true); } @@ -1541,7 +1541,7 @@ if (!shouldUpdateNeedsApplyPass && !needsApplyPass.get(priority, isImportant)) return; - if (state.style()->insideLink() != NotInsideLink) { + if (state.style()->insideLink() != EInsideLink::kNotInsideLink) { for (const auto& matchedProperties : range) { unsigned linkMatchType = matchedProperties.m_types.linkMatchType; // FIXME: It would be nicer to pass these as arguments but that requires
diff --git a/third_party/WebKit/Source/core/dom/DOMTypedArray.h b/third_party/WebKit/Source/core/dom/DOMTypedArray.h index 292003a..9dff983 100644 --- a/third_party/WebKit/Source/core/dom/DOMTypedArray.h +++ b/third_party/WebKit/Source/core/dom/DOMTypedArray.h
@@ -54,7 +54,8 @@ } static ThisType* createOrNull(unsigned length) { - RefPtr<WTF::ArrayBuffer> buffer = WTF::ArrayBuffer::createOrNull(length, 1); + RefPtr<WTF::ArrayBuffer> buffer = + WTF::ArrayBuffer::createOrNull(length, sizeof(ValueType)); return buffer ? create(buffer.release(), 0, length) : nullptr; }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index c6fc0601..8dd0107 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1369,13 +1369,13 @@ // We use HashMap::set over HashMap::add here as we want to // replace the ComputedStyle but not the Node if the Node is // already present. -void Document::addStyleReattachData(Node& node, +void Document::addStyleReattachData(const Node& node, StyleReattachData& styleReattachData) { DCHECK(node.isElementNode() || node.isTextNode()); m_styleReattachDataMap.set(&node, styleReattachData); } -StyleReattachData Document::getStyleReattachData(Node& node) { +StyleReattachData Document::getStyleReattachData(const Node& node) const { return m_styleReattachDataMap.get(&node); }
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 19e980fe..9700908d 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -347,8 +347,8 @@ // just for the web IDL implementation. Element* scrollingElementNoLayout(); - void addStyleReattachData(Node&, StyleReattachData&); - StyleReattachData getStyleReattachData(Node&); + void addStyleReattachData(const Node&, StyleReattachData&); + StyleReattachData getStyleReattachData(const Node&) const; String readyState() const; @@ -1450,7 +1450,7 @@ // This HashMap is used to stash information (ComputedStyle, nextTextSibling) // generated in the Style Resolution phase that is required in the // Layout Tree construction phase. - HeapHashMap<Member<Node>, StyleReattachData> m_styleReattachDataMap; + HeapHashMap<Member<const Node>, StyleReattachData> m_styleReattachDataMap; bool m_wellFormed;
diff --git a/third_party/WebKit/Source/core/dom/Document.idl b/third_party/WebKit/Source/core/dom/Document.idl index 9c10395..826a96d 100644 --- a/third_party/WebKit/Source/core/dom/Document.idl +++ b/third_party/WebKit/Source/core/dom/Document.idl
@@ -78,7 +78,7 @@ [NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); // NonDocumentRootScroller (https://github.com/bokand/NonDocumentRootScroller) - [RaisesException=Setter, RuntimeEnabled=SetRootScroller, Measure] attribute Element? rootScroller; + [RaisesException=Setter, OriginTrialEnabled=RootScroller, Measure] attribute Element? rootScroller; // FIXME: xmlEncoding/xmlVersion/xmlStandalone have been removed from the spec. [MeasureAs=DocumentXMLEncoding] readonly attribute DOMString? xmlEncoding;
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp index 13a714a..a13fa7f 100644 --- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -450,8 +450,8 @@ TEST_F(DocumentTest, SynchronousMutationNotifier) { auto& observer = *new TestSynchronousMutationObserver(document()); - EXPECT_EQ(observer.lifecycleContext(), document()); - EXPECT_EQ(observer.countContextDestroyedCalled(), 0); + EXPECT_EQ(document(), observer.lifecycleContext()); + EXPECT_EQ(0, observer.countContextDestroyedCalled()); Element* divNode = document().createElement("div"); document().body()->appendChild(divNode); @@ -467,18 +467,18 @@ EXPECT_TRUE(observer.removedNodes().isEmpty()); textNode->remove(); - ASSERT_EQ(observer.removedNodes().size(), 1u); + ASSERT_EQ(1u, observer.removedNodes().size()); EXPECT_EQ(textNode, observer.removedNodes()[0]); divNode->removeChildren(); - EXPECT_EQ(observer.removedNodes().size(), 1u) + EXPECT_EQ(1u, observer.removedNodes().size()) << "ContainerNode::removeChildren() doesn't call nodeWillBeRemoved()"; - ASSERT_EQ(observer.removedChildrenNodes().size(), 1u); + ASSERT_EQ(1u, observer.removedChildrenNodes().size()); EXPECT_EQ(divNode, observer.removedChildrenNodes()[0]); document().shutdown(); - EXPECT_EQ(observer.lifecycleContext(), nullptr); - EXPECT_EQ(observer.countContextDestroyedCalled(), 1); + EXPECT_EQ(nullptr, observer.lifecycleContext()); + EXPECT_EQ(1, observer.countContextDestroyedCalled()); } TEST_F(DocumentTest, SynchronousMutationNotifieAppendChild) { @@ -505,12 +505,12 @@ Text* mergeSampleB = document().createTextNode("b123456789"); document().body()->appendChild(mergeSampleB); - EXPECT_EQ(observer.mergeTextNodesRecords().size(), 0u); + EXPECT_EQ(0u, observer.mergeTextNodesRecords().size()); document().body()->normalize(); - ASSERT_EQ(observer.mergeTextNodesRecords().size(), 1u); - EXPECT_EQ(observer.mergeTextNodesRecords()[0]->m_node, mergeSampleB); - EXPECT_EQ(observer.mergeTextNodesRecords()[0]->m_offset, 10u); + ASSERT_EQ(1u, observer.mergeTextNodesRecords().size()); + EXPECT_EQ(mergeSampleB, observer.mergeTextNodesRecords()[0]->m_node); + EXPECT_EQ(10u, observer.mergeTextNodesRecords()[0]->m_offset); } TEST_F(DocumentTest, SynchronousMutationNotifieRemoveChild) { @@ -540,8 +540,8 @@ document().body()->appendChild(splitSample); splitSample->splitText(4, ASSERT_NO_EXCEPTION); - ASSERT_EQ(observer.splitTextNodes().size(), 1u); - EXPECT_EQ(observer.splitTextNodes()[0], splitSample); + ASSERT_EQ(1u, observer.splitTextNodes().size()); + EXPECT_EQ(splitSample, observer.splitTextNodes()[0]); } TEST_F(DocumentTest, SynchronousMutationNotifierUpdateCharacterData) { @@ -559,35 +559,35 @@ Text* replaceSample = document().createTextNode("c123456789"); document().body()->appendChild(replaceSample); - EXPECT_EQ(observer.updatedCharacterDataRecords().size(), 0u); + EXPECT_EQ(0u, observer.updatedCharacterDataRecords().size()); appendSample->appendData("abc"); - ASSERT_EQ(observer.updatedCharacterDataRecords().size(), 1u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[0]->m_node, appendSample); - EXPECT_EQ(observer.updatedCharacterDataRecords()[0]->m_offset, 10u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[0]->m_oldLength, 0u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[0]->m_newLength, 3u); + ASSERT_EQ(1u, observer.updatedCharacterDataRecords().size()); + EXPECT_EQ(appendSample, observer.updatedCharacterDataRecords()[0]->m_node); + EXPECT_EQ(10u, observer.updatedCharacterDataRecords()[0]->m_offset); + EXPECT_EQ(0u, observer.updatedCharacterDataRecords()[0]->m_oldLength); + EXPECT_EQ(3u, observer.updatedCharacterDataRecords()[0]->m_newLength); deleteSample->deleteData(3, 4, ASSERT_NO_EXCEPTION); - ASSERT_EQ(observer.updatedCharacterDataRecords().size(), 2u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[1]->m_node, deleteSample); - EXPECT_EQ(observer.updatedCharacterDataRecords()[1]->m_offset, 3u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[1]->m_oldLength, 4u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[1]->m_newLength, 0u); + ASSERT_EQ(2u, observer.updatedCharacterDataRecords().size()); + EXPECT_EQ(deleteSample, observer.updatedCharacterDataRecords()[1]->m_node); + EXPECT_EQ(3u, observer.updatedCharacterDataRecords()[1]->m_offset); + EXPECT_EQ(4u, observer.updatedCharacterDataRecords()[1]->m_oldLength); + EXPECT_EQ(0u, observer.updatedCharacterDataRecords()[1]->m_newLength); insertSample->insertData(3, "def", ASSERT_NO_EXCEPTION); - ASSERT_EQ(observer.updatedCharacterDataRecords().size(), 3u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[2]->m_node, insertSample); - EXPECT_EQ(observer.updatedCharacterDataRecords()[2]->m_offset, 3u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[2]->m_oldLength, 0u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[2]->m_newLength, 3u); + ASSERT_EQ(3u, observer.updatedCharacterDataRecords().size()); + EXPECT_EQ(insertSample, observer.updatedCharacterDataRecords()[2]->m_node); + EXPECT_EQ(3u, observer.updatedCharacterDataRecords()[2]->m_offset); + EXPECT_EQ(0u, observer.updatedCharacterDataRecords()[2]->m_oldLength); + EXPECT_EQ(3u, observer.updatedCharacterDataRecords()[2]->m_newLength); replaceSample->replaceData(6, 4, "ghi", ASSERT_NO_EXCEPTION); - ASSERT_EQ(observer.updatedCharacterDataRecords().size(), 4u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[3]->m_node, replaceSample); - EXPECT_EQ(observer.updatedCharacterDataRecords()[3]->m_offset, 6u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[3]->m_oldLength, 4u); - EXPECT_EQ(observer.updatedCharacterDataRecords()[3]->m_newLength, 3u); + ASSERT_EQ(4u, observer.updatedCharacterDataRecords().size()); + EXPECT_EQ(replaceSample, observer.updatedCharacterDataRecords()[3]->m_node); + EXPECT_EQ(6u, observer.updatedCharacterDataRecords()[3]->m_offset); + EXPECT_EQ(4u, observer.updatedCharacterDataRecords()[3]->m_oldLength); + EXPECT_EQ(3u, observer.updatedCharacterDataRecords()[3]->m_newLength); } // This tests that meta-theme-color can be found correctly
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index 600af2f1..3eb14f3b 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1826,6 +1826,14 @@ return document().contextDocument(); } +void Node::willMoveToNewDocument(Document& oldDocument, Document& newDocument) { + if (!oldDocument.frameHost() || + oldDocument.frameHost() == newDocument.frameHost()) + return; + + oldDocument.frameHost()->eventHandlerRegistry().didMoveOutOfFrameHost(*this); +} + void Node::didMoveToNewDocument(Document& oldDocument) { TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(oldDocument); @@ -1838,14 +1846,10 @@ } oldDocument.markers().removeMarkers(this); - if (oldDocument.frameHost() && !document().frameHost()) - oldDocument.frameHost()->eventHandlerRegistry().didMoveOutOfFrameHost( - *this); - else if (document().frameHost() && !oldDocument.frameHost()) + if (document().frameHost() && + document().frameHost() != oldDocument.frameHost()) { document().frameHost()->eventHandlerRegistry().didMoveIntoFrameHost(*this); - else if (oldDocument.frameHost() != document().frameHost()) - EventHandlerRegistry::didMoveBetweenFrameHosts( - *this, oldDocument.frameHost(), document().frameHost()); + } if (const HeapVector<TraceWrapperMember<MutationObserverRegistration>>* registry = mutationObserverRegistry()) {
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h index b3f64137..c02e8527 100644 --- a/third_party/WebKit/Source/core/dom/Node.h +++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -867,6 +867,8 @@ Node(TreeScope*, ConstructionType); + virtual void willMoveToNewDocument(Document& oldDocument, + Document& newDocument); virtual void didMoveToNewDocument(Document& oldDocument); void addedEventListener(const AtomicString& eventType,
diff --git a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp index 8600f77..bea9098 100644 --- a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp +++ b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
@@ -128,6 +128,8 @@ Document& oldDocument, Document& newDocument) const { DCHECK_NE(oldDocument, newDocument); + // Note: at the start of this function, node.document() may already have + // changed to match |newDocument|, which is why |oldDocument| is passed in. if (node.hasRareData()) { NodeRareData* rareData = node.rareData(); @@ -135,6 +137,7 @@ rareData->nodeLists()->adoptDocument(oldDocument, newDocument); } + node.willMoveToNewDocument(oldDocument, newDocument); oldDocument.moveNodeIteratorsToNewDocument(node, newDocument); if (node.getCustomElementState() == CustomElementState::Custom) {
diff --git a/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp b/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp index 17d0f56..dd0fec9 100644 --- a/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp +++ b/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp
@@ -119,22 +119,22 @@ const AtomicString& attribute = linkAttribute(element); if (attribute.isNull()) - return NotInsideLink; // This can happen for <img usemap> + return EInsideLink::kNotInsideLink; // This can happen for <img usemap> // An empty attribute refers to the document itself which is always // visited. It is useful to check this explicitly so that visited // links can be tested in platform independent manner, without // explicit support in the test harness. if (attribute.isEmpty()) - return InsideVisitedLink; + return EInsideLink::kInsideVisitedLink; if (LinkHash hash = linkHashForElement(element, attribute)) { m_linksCheckedForVisitedState.add(hash); if (Platform::current()->isLinkVisited(hash)) - return InsideVisitedLink; + return EInsideLink::kInsideVisitedLink; } - return InsideUnvisitedLink; + return EInsideLink::kInsideUnvisitedLink; } DEFINE_TRACE(VisitedLinkState) {
diff --git a/third_party/WebKit/Source/core/dom/VisitedLinkState.h b/third_party/WebKit/Source/core/dom/VisitedLinkState.h index ebe3a6a..284b979 100644 --- a/third_party/WebKit/Source/core/dom/VisitedLinkState.h +++ b/third_party/WebKit/Source/core/dom/VisitedLinkState.h
@@ -52,7 +52,7 @@ EInsideLink determineLinkState(const Element& element) { if (element.isLink()) return determineLinkStateSlowCase(element); - return NotInsideLink; + return EInsideLink::kNotInsideLink; } DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/editing/CaretBase.cpp b/third_party/WebKit/Source/core/editing/CaretBase.cpp index 8b150d8..16e0f02e 100644 --- a/third_party/WebKit/Source/core/editing/CaretBase.cpp +++ b/third_party/WebKit/Source/core/editing/CaretBase.cpp
@@ -113,10 +113,6 @@ caretLocalRect); } -LayoutRect CaretBase::computeCaretRect(const VisiblePosition& caretPosition) { - return computeCaretRect(caretPosition.toPositionWithAffinity()); -} - IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) { LayoutBlock* caretPainter = caretLayoutObject(node); @@ -168,11 +164,10 @@ void CaretBase::paintCaret(Node* node, GraphicsContext& context, - const DisplayItemClient& client, const LayoutRect& caretLocalRect, const LayoutPoint& paintOffset, DisplayItem::Type displayItemType) { - if (DrawingRecorder::useCachedDrawingIfPossible(context, client, + if (DrawingRecorder::useCachedDrawingIfPossible(context, *this, displayItemType)) return; @@ -184,7 +179,7 @@ const Color caretColor = node->layoutObject()->resolveColor(CSSPropertyCaretColor); IntRect paintRect = pixelSnappedIntRect(drawingRect); - DrawingRecorder drawingRecorder(context, client, DisplayItem::kCaret, + DrawingRecorder drawingRecorder(context, *this, DisplayItem::kCaret, paintRect); context.fillRect(paintRect, caretColor); }
diff --git a/third_party/WebKit/Source/core/editing/CaretBase.h b/third_party/WebKit/Source/core/editing/CaretBase.h index c29b3f5..993371d 100644 --- a/third_party/WebKit/Source/core/editing/CaretBase.h +++ b/third_party/WebKit/Source/core/editing/CaretBase.h
@@ -27,7 +27,7 @@ #ifndef CaretBase_h #define CaretBase_h -#include "core/editing/VisiblePosition.h" +#include "core/editing/PositionWithAffinity.h" #include "platform/geometry/IntRect.h" #include "platform/geometry/LayoutRect.h" #include "platform/graphics/paint/DisplayItem.h" @@ -50,26 +50,17 @@ // PositionWithAffinity version if possible. // A position in HTMLTextFromControlElement is a typical example. static LayoutRect computeCaretRect(const PositionWithAffinity& caretPosition); - - // TODO(yosin): We should move |computeCaretRect()| with |VisiblePosition| to - // "FrameCaret.cpp" as static file local function. - static LayoutRect computeCaretRect(const VisiblePosition& caretPosition); - - // TODO(yosin): We should move |absoluteBoundsForLocalRect()| with - // |VisiblePosition| to "FrameCaret.cpp" as static file local function. static IntRect absoluteBoundsForLocalRect(Node*, const LayoutRect&); // TODO(yosin): We should move |shouldRepaintCaret()| to "FrameCaret.cpp" as // static file local function. static bool shouldRepaintCaret(Node&); - // TODO(yosin): We should make |paintCaret()| to non-static member and get rid - // |DisplayItemClient| parameter. - static void paintCaret(Node*, - GraphicsContext&, - const DisplayItemClient&, - const LayoutRect& caretLocalRect, - const LayoutPoint&, - DisplayItem::Type); + + void paintCaret(Node*, + GraphicsContext&, + const LayoutRect& caretLocalRect, + const LayoutPoint&, + DisplayItem::Type); static LayoutBlock* caretLayoutObject(Node*); void invalidateLocalCaretRect(Node*, const LayoutRect&);
diff --git a/third_party/WebKit/Source/core/editing/DragCaretController.cpp b/third_party/WebKit/Source/core/editing/DragCaretController.cpp index 6aff51fb..0ea817c 100644 --- a/third_party/WebKit/Source/core/editing/DragCaretController.cpp +++ b/third_party/WebKit/Source/core/editing/DragCaretController.cpp
@@ -111,9 +111,8 @@ GraphicsContext& context, const LayoutPoint& paintOffset) const { if (m_position.anchorNode()->document().frame() == frame) { - CaretBase::paintCaret(m_position.anchorNode(), context, *m_caretBase, - m_caretLocalRect, paintOffset, - DisplayItem::kDragCaret); + m_caretBase->paintCaret(m_position.anchorNode(), context, m_caretLocalRect, + paintOffset, DisplayItem::kDragCaret); } }
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index ca05390e..0945f8a 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -352,7 +352,7 @@ if (isTypingAction) { DCHECK(frame().document()); TypingCommand::deleteKeyPressed( - *frame().document(), source, + *frame().document(), canSmartCopyOrDelete() ? TypingCommand::SmartDelete : 0, granularity); revealSelectionAfterEditingOperation(); } else { @@ -374,13 +374,13 @@ case DeleteDirection::Forward: DCHECK(frame().document()); TypingCommand::forwardDeleteKeyPressed( - *frame().document(), source, &editingState, options, granularity); + *frame().document(), &editingState, options, granularity); if (editingState.isAborted()) return false; break; case DeleteDirection::Backward: DCHECK(frame().document()); - TypingCommand::deleteKeyPressed(*frame().document(), source, options, + TypingCommand::deleteKeyPressed(*frame().document(), options, granularity); break; } @@ -396,8 +396,9 @@ return true; } +// TODO(chongz): Pass |EditCommandSource| to |CompositeEditCommand|. void Editor::deleteSelectionWithSmartDelete( - EditCommandSource source, + EditCommandSource, DeleteMode deleteMode, InputEvent::InputType inputType, const Position& referenceMovePosition) { @@ -412,7 +413,7 @@ *frame().document(), deleteMode == DeleteMode::Smart, kMergeBlocksAfterDelete, kExpandForSpecialElements, kSanitizeMarkup, inputType, referenceMovePosition) - ->apply(source); + ->apply(); } void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace) { @@ -590,7 +591,8 @@ return smartInsertDeleteEnabled() && pasteboard->canSmartReplace(); } -void Editor::replaceSelectionWithFragment(EditCommandSource source, +// TODO(chongz): Pass |EditCommandSource| to |CompositeEditCommand|. +void Editor::replaceSelectionWithFragment(EditCommandSource, DocumentFragment* fragment, bool selectReplacement, bool smartReplace, @@ -613,7 +615,7 @@ DCHECK(frame().document()); ReplaceSelectionCommand::create(*frame().document(), fragment, options, inputType) - ->apply(source); + ->apply(); revealSelectionAfterEditingOperation(); } @@ -641,7 +643,7 @@ DCHECK(frame().document()); ReplaceSelectionCommand::create(*frame().document(), fragment, options, InputEvent::InputType::InsertFromDrop) - ->apply(EditCommandSource::kMenuOrKeyBinding); + ->apply(); } bool Editor::deleteSelectionAfterDraggingWithEvents( @@ -728,9 +730,10 @@ client().respondToChangedContents(); } -void Editor::removeFormattingAndStyle(EditCommandSource source) { +// TODO(chongz): Pass |EditCommandSource| to |CompositeEditCommand|. +void Editor::removeFormattingAndStyle(EditCommandSource) { DCHECK(frame().document()); - RemoveFormatCommand::create(*frame().document())->apply(source); + RemoveFormatCommand::create(*frame().document())->apply(); } void Editor::registerCommandGroup(CompositeEditCommand* commandGroupWrapper) { @@ -769,13 +772,14 @@ DCHECK(frame().document()); ApplyStyleCommand::create(*frame().document(), EditingStyle::create(style), inputType) - ->apply(source); + ->apply(); } break; } } -void Editor::applyParagraphStyle(EditCommandSource source, +// TODO(chongz): Pass |EditCommandSource| to |CompositeEditCommand|. +void Editor::applyParagraphStyle(EditCommandSource, StylePropertySet* style, InputEvent::InputType inputType) { if (frame().selection().isNone() || !style) @@ -783,7 +787,7 @@ DCHECK(frame().document()); ApplyStyleCommand::create(*frame().document(), EditingStyle::create(style), inputType, ApplyStyleCommand::ForceBlockProperties) - ->apply(source); + ->apply(); } void Editor::applyStyleToSelection(EditCommandSource source, @@ -1011,7 +1015,7 @@ // Insert the text TypingCommand::insertText( - *selection.start().document(), source, text, selection, + *selection.start().document(), text, selection, selectInsertedText ? TypingCommand::SelectInsertedText : 0, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm @@ -1037,11 +1041,7 @@ VisiblePosition caret = frame().selection().selection().visibleStart(); bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); DCHECK(frame().document()); - // we can pass |EditCommandSource::kMenuOrKeyBinding| because - // |insertLineBreak()| is only used by |Editor::handleTextEvent()| and - // |Editor::insertParagraphSeparator()|. - if (!TypingCommand::insertLineBreak(*frame().document(), - EditCommandSource::kMenuOrKeyBinding)) + if (!TypingCommand::insertLineBreak(*frame().document())) return false; revealSelectionAfterEditingOperation( alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded @@ -1061,11 +1061,7 @@ bool alignToEdge = isEndOfEditableOrNonEditableContent(caret); DCHECK(frame().document()); EditingState editingState; - // We can |EditCommandSource::kMenuOrKeyBinding| because - // |Editor::insertParagraphSeparator()| is only used by - // |Editor::handleTextEvent()|. - if (!TypingCommand::insertParagraphSeparator( - *frame().document(), EditCommandSource::kMenuOrKeyBinding)) + if (!TypingCommand::insertParagraphSeparator(*frame().document())) return false; revealSelectionAfterEditingOperation( alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded @@ -1450,7 +1446,8 @@ startCaretRect.height()); } -void Editor::computeAndSetTypingStyle(EditCommandSource source, +// TODO(chongz): Pass |EditCommandSource| to |CompositeEditCommand|. +void Editor::computeAndSetTypingStyle(EditCommandSource, StylePropertySet* style, InputEvent::InputType inputType) { if (!style || style->isEmpty()) { @@ -1476,7 +1473,7 @@ if (!blockStyle->isEmpty()) { DCHECK(frame().document()); ApplyStyleCommand::create(*frame().document(), blockStyle, inputType) - ->apply(source); + ->apply(); } // Set the remaining style as the typing style.
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp index a6329c5..5e5eee8 100644 --- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp +++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
@@ -234,7 +234,8 @@ } return CaretBase::absoluteBoundsForLocalRect( caretNode, - CaretBase::computeCaretRect(createVisiblePosition(caretPosition()))); + CaretBase::computeCaretRect( + createVisiblePosition(caretPosition()).toPositionWithAffinity())); } void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) { @@ -255,8 +256,8 @@ const LayoutRect caretLocalRect = CaretBase::computeCaretRect(caretPosition()); - CaretBase::paintCaret(caretPosition().anchorNode(), context, *m_caretBase, - caretLocalRect, paintOffset, DisplayItem::kCaret); + m_caretBase->paintCaret(caretPosition().anchorNode(), context, caretLocalRect, + paintOffset, DisplayItem::kCaret); } void FrameCaret::dataWillChange(const CharacterData& node) {
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index 3a1071d..1b11d96a 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -144,9 +144,8 @@ switch (compositionType) { case TypingCommand::TextCompositionType::TextCompositionUpdate: case TypingCommand::TextCompositionType::TextCompositionConfirm: - TypingCommand::insertText( - *frame.document(), EditCommandSource::kMenuOrKeyBinding, text, - options, compositionType, isIncrementalInsertion); + TypingCommand::insertText(*frame.document(), text, options, + compositionType, isIncrementalInsertion); break; case TypingCommand::TextCompositionType::TextCompositionCancel: // TODO(chongz): Use TypingCommand::insertText after TextEvent was @@ -306,10 +305,8 @@ // If text is empty, then delete the old composition here. If text is // non-empty, InsertTextCommand::input will delete the old composition with // an optimized replace operation. - if (text.isEmpty()) { - TypingCommand::deleteSelection(document(), - EditCommandSource::kMenuOrKeyBinding, 0); - } + if (text.isEmpty()) + TypingCommand::deleteSelection(document(), 0); clear(); @@ -538,7 +535,6 @@ // composition, however some IME (e.g. Japanese IBus-Anthy) did this, so // we simply delete selection without sending extra events. TypingCommand::deleteSelection(document(), - EditCommandSource::kMenuOrKeyBinding, TypingCommand::PreventSpellChecking); } @@ -797,8 +793,7 @@ dispatchBeforeInputEditorCommand( document().focusedElement(), InputEvent::InputType::DeleteContentBackward, new RangeVector(1, m_frame->selection().firstRange())); - TypingCommand::deleteSelection(document(), - EditCommandSource::kMenuOrKeyBinding); + TypingCommand::deleteSelection(document()); } // TODO(yabinh): We should reduce the number of selectionchange events. @@ -833,8 +828,7 @@ const int adjustedStart = start - static_cast<int>(diff); if (!setSelectionOffsets(PlainTextRange(adjustedStart, selectionStart))) return; - TypingCommand::deleteSelection(document(), - EditCommandSource::kMenuOrKeyBinding); + TypingCommand::deleteSelection(document()); selectionEnd = selectionEnd - (selectionStart - adjustedStart); selectionStart = adjustedStart; @@ -859,8 +853,7 @@ const int adjustedEnd = end + static_cast<int>(diff); if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) return; - TypingCommand::deleteSelection(document(), - EditCommandSource::kMenuOrKeyBinding); + TypingCommand::deleteSelection(document()); } setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd));
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommandTest.cpp index 40129f6..cd06bf1 100644 --- a/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommandTest.cpp
@@ -46,7 +46,7 @@ FormatBlockCommand* command = FormatBlockCommand::create(document(), HTMLNames::footerTag); - command->apply(EditCommandSource::kMenuOrKeyBinding); + command->apply(); EXPECT_EQ( "<body contenteditable=\"false\">\n" @@ -70,7 +70,7 @@ IndentOutdentCommand* command = IndentOutdentCommand::create(document(), IndentOutdentCommand::Indent); - command->apply(EditCommandSource::kMenuOrKeyBinding); + command->apply(); EXPECT_EQ( "<head><style>li:first-child { visibility:visible; }</style></head>"
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommandTest.cpp index 5357b8e3..24af3cb0 100644 --- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommandTest.cpp
@@ -44,7 +44,7 @@ ApplyStyleCommand::create(document(), EditingStyle::create(style), InputEvent::InputType::FormatJustifyCenter, ApplyStyleCommand::ForceBlockProperties) - ->apply(EditCommandSource::kDOM); + ->apply(); // Shouldn't crash. }
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp index 57d9249..1774c34 100644 --- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -187,7 +187,7 @@ DCHECK(isTopLevelCommand() || !m_composition); } -bool CompositeEditCommand::apply(EditCommandSource source) { +bool CompositeEditCommand::apply() { DCHECK(!isCommandGroupWrapper()); if (!endingSelection().isContentRichlyEditable()) { switch (inputType()) { @@ -223,9 +223,6 @@ // the creation of VisiblePositions). document().updateStyleAndLayoutIgnorePendingStylesheets(); - if (!willApplyEditing(source)) - return false; - LocalFrame* frame = document().frame(); DCHECK(frame); EditingState editingState; @@ -252,11 +249,6 @@ return command->m_composition.get(); } -bool CompositeEditCommand::willApplyEditing(EditCommandSource) { - // TODO(chongz): Move all the 'beforeinput' dispatching logic here. - return true; -} - bool CompositeEditCommand::preservesTypingStyle() const { return false; }
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h index 54ca077..24d67a7 100644 --- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h +++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.h
@@ -96,7 +96,7 @@ ~CompositeEditCommand() override; // Returns |false| if the command failed. e.g. It's aborted. - bool apply(EditCommandSource); + bool apply(); bool isFirstCommand(EditCommand* command) { return !m_commands.isEmpty() && m_commands.front() == command; } @@ -118,15 +118,6 @@ protected: explicit CompositeEditCommand(Document&); - // TODO(chongz): Implement "beforeinput" as described below: - // Fires "beforeinput" and will return |false| to cancel applying editing if - // * "beforeinput" was canceled, or - // * |frame| was destroyed by event handlers. - // |willApplyEditing()| should be called from - // * |CompositeEditCommand::apply()|, and - // * |TypingCommand::willAddTypingToOpenCommand()|. - bool willApplyEditing(EditCommandSource); - // // sugary-sweet convenience functions to help create and apply edit commands // in composite commands
diff --git a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommandTest.cpp index b317923..d9851af 100644 --- a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommandTest.cpp
@@ -51,8 +51,7 @@ kNoExpandForSpecialElements, kSanitizeMarkup, InputEvent::InputType::DeleteByCut); - EXPECT_TRUE(command->apply(EditCommandSource::kMenuOrKeyBinding)) - << "the delete command should have succeeded"; + EXPECT_TRUE(command->apply()) << "the delete command should have succeeded"; EXPECT_EQ("<div contenteditable=\"true\"><br></div>", document().body()->innerHTML()); EXPECT_TRUE(frame->selection().isCaret());
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp index 22ef3baf..d6da2ae 100644 --- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -363,14 +363,14 @@ } static bool executeInsertFragment(LocalFrame& frame, - EditCommandSource source, + EditCommandSource, DocumentFragment* fragment) { DCHECK(frame.document()); return ReplaceSelectionCommand::create( *frame.document(), fragment, ReplaceSelectionCommand::PreventNesting, InputEvent::InputType::None) - ->apply(source); + ->apply(); } static bool executeInsertElement(LocalFrame& frame, @@ -541,12 +541,12 @@ static bool executeCreateLink(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String& value) { if (value.isEmpty()) return false; DCHECK(frame.document()); - return CreateLinkCommand::create(*frame.document(), value)->apply(source); + return CreateLinkCommand::create(*frame.document(), value)->apply(); } static bool executeCut(LocalFrame& frame, @@ -593,10 +593,9 @@ // time, siding with IE, not Firefox). DCHECK(frame.document()); TypingCommand::deleteKeyPressed( - *frame.document(), source, - frame.selection().granularity() == WordGranularity - ? TypingCommand::SmartDelete - : 0); + *frame.document(), frame.selection().granularity() == WordGranularity + ? TypingCommand::SmartDelete + : 0); return true; } NOTREACHED(); @@ -756,7 +755,7 @@ static bool executeFormatBlock(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String& value) { String tagName = value.lower(); if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>') @@ -771,7 +770,7 @@ DCHECK(frame.document()); FormatBlockCommand* command = FormatBlockCommand::create(*frame.document(), qualifiedTagName); - command->apply(source); + command->apply(); return command->didApply(); } @@ -791,8 +790,7 @@ // only needed for backward compatibility with ourselves, and for // consistency with Delete. DCHECK(frame.document()); - TypingCommand::forwardDeleteKeyPressed(*frame.document(), source, - &editingState); + TypingCommand::forwardDeleteKeyPressed(*frame.document(), &editingState); if (editingState.isAborted()) return false; return true; @@ -811,12 +809,12 @@ static bool executeIndent(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); return IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Indent) - ->apply(source); + ->apply(); } static bool executeInsertBacktab(LocalFrame& frame, @@ -876,7 +874,7 @@ // is only needed for backward compatibility with ourselves, and for // consistency with other commands. DCHECK(frame.document()); - return TypingCommand::insertLineBreak(*frame.document(), source); + return TypingCommand::insertLineBreak(*frame.document()); } NOTREACHED(); return false; @@ -897,29 +895,29 @@ static bool executeInsertNewlineInQuotedContent(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); return TypingCommand::insertParagraphSeparatorInQuotedContent( - *frame.document(), source); + *frame.document()); } static bool executeInsertOrderedList(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); return InsertListCommand::create(*frame.document(), InsertListCommand::OrderedList) - ->apply(source); + ->apply(); } static bool executeInsertParagraph(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); - return TypingCommand::insertParagraphSeparator(*frame.document(), source); + return TypingCommand::insertParagraphSeparator(*frame.document()); } static bool executeInsertTab(LocalFrame& frame, @@ -935,21 +933,21 @@ static bool executeInsertText(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String& value) { DCHECK(frame.document()); - TypingCommand::insertText(*frame.document(), source, value, 0); + TypingCommand::insertText(*frame.document(), value, 0); return true; } static bool executeInsertUnorderedList(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); return InsertListCommand::create(*frame.document(), InsertListCommand::UnorderedList) - ->apply(source); + ->apply(); } static bool executeJustifyCenter(LocalFrame& frame, @@ -1470,12 +1468,12 @@ static bool executeOutdent(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); return IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Outdent) - ->apply(source); + ->apply(); } static bool executeToggleOverwrite(LocalFrame& frame, @@ -1775,10 +1773,10 @@ static bool executeUnlink(LocalFrame& frame, Event*, - EditCommandSource source, + EditCommandSource, const String&) { DCHECK(frame.document()); - return UnlinkCommand::create(*frame.document())->apply(source); + return UnlinkCommand::create(*frame.document())->apply(); } static bool executeUnscript(LocalFrame& frame,
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertListCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/InsertListCommandTest.cpp index bea2af380..c77927164 100644 --- a/third_party/WebKit/Source/core/editing/commands/InsertListCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/InsertListCommandTest.cpp
@@ -42,7 +42,7 @@ InsertListCommand* command = InsertListCommand::create(document(), InsertListCommand::OrderedList); // This should not DCHECK. - EXPECT_TRUE(command->apply(EditCommandSource::kMenuOrKeyBinding)) + EXPECT_TRUE(command->apply()) << "The insert ordered list command should have succeeded"; EXPECT_EQ("<ol><li>d</li></ol>", document().body()->innerHTML()); }
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp index 7eb43fe..3624499 100644 --- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp
@@ -47,8 +47,7 @@ ReplaceSelectionCommand* command = ReplaceSelectionCommand::create(document(), fragment, options); - EXPECT_TRUE(command->apply(EditCommandSource::kMenuOrKeyBinding)) - << "the replace command should have succeeded"; + EXPECT_TRUE(command->apply()) << "the replace command should have succeeded"; EXPECT_EQ("foo", document().body()->innerHTML()) << "no DOM tree mutation"; } @@ -71,8 +70,7 @@ ReplaceSelectionCommand* command = ReplaceSelectionCommand::create(document(), fragment, options); - EXPECT_TRUE(command->apply(EditCommandSource::kMenuOrKeyBinding)) - << "the replace command should have succeeded"; + EXPECT_TRUE(command->apply()) << "the replace command should have succeeded"; EXPECT_EQ("<b>t</b>bar<b>ext</b>", document().body()->innerHTML()) << "'bar' should have been inserted"; } @@ -95,8 +93,7 @@ ReplaceSelectionCommand::CommandOptions options = 0; ReplaceSelectionCommand* command = ReplaceSelectionCommand::create(document(), fragment, options); - EXPECT_TRUE(command->apply(EditCommandSource::kMenuOrKeyBinding)) - << "the replace command should have succeeded"; + EXPECT_TRUE(command->apply()) << "the replace command should have succeeded"; EXPECT_EQ( "<head><style>foo { bar: baz; }</style></head>"
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp index 85fbcce8..89d68d2 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -122,39 +122,6 @@ return event->text().length(); } -InputEvent::InputType inputTypeForTypingCommand( - TypingCommand::ETypingCommand commandType, - TextGranularity granularity, - TypingCommand::TextCompositionType compositionType) { - using InputType = InputEvent::InputType; - - switch (commandType) { - // TODO(chongz): |DeleteSelection| is used by IME but we don't have - // direction info. - case TypingCommand::DeleteSelection: - return InputType::DeleteContentBackward; - case TypingCommand::DeleteKey: - if (compositionType != TypingCommand::TextCompositionNone) - return InputType::DeleteComposedCharacterBackward; - return deletionInputTypeFromTextGranularity(DeleteDirection::Backward, - granularity); - case TypingCommand::ForwardDeleteKey: - if (compositionType != TypingCommand::TextCompositionNone) - return InputType::DeleteComposedCharacterForward; - return deletionInputTypeFromTextGranularity(DeleteDirection::Forward, - granularity); - case TypingCommand::InsertText: - return InputType::InsertText; - case TypingCommand::InsertLineBreak: - return InputType::InsertLineBreak; - case TypingCommand::InsertParagraphSeparator: - case TypingCommand::InsertParagraphSeparatorInQuotedContent: - return InputType::InsertParagraph; - default: - return InputType::None; - } -} - } // anonymous namespace using namespace HTMLNames; @@ -178,14 +145,10 @@ m_shouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator), m_shouldPreventSpellChecking(options & PreventSpellChecking) { - m_inputType = inputTypeForTypingCommand(m_commandType, m_granularity, - m_compositionType); updatePreservesTypingStyle(m_commandType); } -void TypingCommand::deleteSelection(Document& document, - EditCommandSource source, - Options options) { +void TypingCommand::deleteSelection(Document& document, Options options) { LocalFrame* frame = document.frame(); DCHECK(frame); @@ -198,14 +161,6 @@ lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking); - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::DeleteContentBackward)) - return; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - // InputMethodController uses this function to delete composition // selection. It won't be aborted. lastTypingCommand->deleteSelection(options & SmartDelete, @@ -213,11 +168,10 @@ return; } - TypingCommand::create(document, DeleteSelection, "", options)->apply(source); + TypingCommand::create(document, DeleteSelection, "", options)->apply(); } void TypingCommand::deleteKeyPressed(Document& document, - EditCommandSource source, Options options, TextGranularity granularity) { if (granularity == CharacterGranularity) { @@ -232,15 +186,6 @@ frame); lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking); - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::DeleteContentBackward)) - return; - - // TODO(editing-dev): The use of - // updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. - // See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - EditingState editingState; lastTypingCommand->deleteKeyPressed(granularity, options & KillRing, &editingState); @@ -249,12 +194,10 @@ } } - TypingCommand::create(document, DeleteKey, "", options, granularity) - ->apply(source); + TypingCommand::create(document, DeleteKey, "", options, granularity)->apply(); } void TypingCommand::forwardDeleteKeyPressed(Document& document, - EditCommandSource source, EditingState* editingState, Options options, TextGranularity granularity) { @@ -267,14 +210,6 @@ updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand, frame); lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking); - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::DeleteContentForward)) - return; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - lastTypingCommand->forwardDeleteKeyPressed( granularity, options & KillRing, editingState); return; @@ -282,13 +217,13 @@ } TypingCommand::create(document, ForwardDeleteKey, "", options, granularity) - ->apply(source); + ->apply(); } String TypingCommand::textDataForInputEvent() const { - if (m_inputType == InputEvent::InputType::InsertText) + if (m_commands.isEmpty() || isIncrementalInsertion()) return m_textToInsert; - return CompositeEditCommand::textDataForInputEvent(); + return m_commands.back()->textDataForInputEvent(); } void TypingCommand::updateSelectionIfDifferentFromCurrentSelection( @@ -304,7 +239,6 @@ } void TypingCommand::insertText(Document& document, - EditCommandSource source, const String& text, Options options, TextCompositionType composition, @@ -316,7 +250,7 @@ document.frame()->spellChecker().updateMarkersForWordsAffectedByEditing( isSpaceOrNewline(text[0])); - insertText(document, source, text, frame->selection().selection(), options, + insertText(document, text, frame->selection().selection(), options, composition, isIncrementalInsertion); } @@ -344,7 +278,6 @@ // FIXME: We shouldn't need to take selectionForInsertion. It should be // identical to FrameSelection's current selection. void TypingCommand::insertText(Document& document, - EditCommandSource source, const String& text, const VisibleSelection& selectionForInsertion, Options options, @@ -391,16 +324,8 @@ options & RetainAutocorrectionIndicator); lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking); - lastTypingCommand->m_isIncrementalInsertion = isIncrementalInsertion; - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::InsertText, newText)) - return; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - EditingState editingState; + lastTypingCommand->m_isIncrementalInsertion = isIncrementalInsertion; lastTypingCommand->insertText(newText, options & SelectInsertedText, &editingState); @@ -426,7 +351,7 @@ command->setEndingVisibleSelection(selectionForInsertion); } command->m_isIncrementalInsertion = isIncrementalInsertion; - const bool aborted = !(command->apply(source)); + const bool aborted = !(command->apply()); if (changeSelection) { command->setEndingVisibleSelection(currentSelection); @@ -446,40 +371,22 @@ } } -bool TypingCommand::insertLineBreak(Document& document, - EditCommandSource source) { +bool TypingCommand::insertLineBreak(Document& document) { if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document.frame())) { lastTypingCommand->setShouldRetainAutocorrectionIndicator(false); - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::InsertLineBreak)) - return false; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - EditingState editingState; lastTypingCommand->insertLineBreak(&editingState); return !editingState.isAborted(); } - return TypingCommand::create(document, InsertLineBreak, "", 0)->apply(source); + return TypingCommand::create(document, InsertLineBreak, "", 0)->apply(); } bool TypingCommand::insertParagraphSeparatorInQuotedContent( - Document& document, - EditCommandSource source) { + Document& document) { if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document.frame())) { - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::InsertParagraph)) - return false; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - EditingState editingState; lastTypingCommand->insertParagraphSeparatorInQuotedContent(&editingState); return !editingState.isAborted(); @@ -487,29 +394,20 @@ return TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent) - ->apply(source); + ->apply(); } -bool TypingCommand::insertParagraphSeparator(Document& document, - EditCommandSource source) { +bool TypingCommand::insertParagraphSeparator(Document& document) { if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document.frame())) { lastTypingCommand->setShouldRetainAutocorrectionIndicator(false); - if (!lastTypingCommand->willAddTypingToOpenCommand( - source, InputEvent::InputType::InsertParagraph)) - return false; - - // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets - // needs to be audited. See http://crbug.com/590369 for more details. - document.updateStyleAndLayoutIgnorePendingStylesheets(); - EditingState editingState; lastTypingCommand->insertParagraphSeparator(&editingState); return !editingState.isAborted(); } return TypingCommand::create(document, InsertParagraphSeparator, "", 0) - ->apply(source); + ->apply(); } TypingCommand* TypingCommand::lastTypingCommandIfStillOpenForTyping( @@ -567,15 +465,33 @@ } InputEvent::InputType TypingCommand::inputType() const { - return m_inputType; -} + using InputType = InputEvent::InputType; -bool TypingCommand::willAddTypingToOpenCommand(EditCommandSource source, - InputEvent::InputType inputType, - const String& text) { - m_inputType = inputType; - m_textToInsert = text; - return willApplyEditing(source); + switch (m_commandType) { + // TODO(chongz): |DeleteSelection| is used by IME but we don't have + // direction info. + case DeleteSelection: + return InputType::DeleteContentBackward; + case DeleteKey: + if (m_compositionType != TextCompositionNone) + return InputType::DeleteComposedCharacterBackward; + return deletionInputTypeFromTextGranularity(DeleteDirection::Backward, + m_granularity); + case ForwardDeleteKey: + if (m_compositionType != TextCompositionNone) + return InputType::DeleteComposedCharacterForward; + return deletionInputTypeFromTextGranularity(DeleteDirection::Forward, + m_granularity); + case InsertText: + return InputType::InsertText; + case InsertLineBreak: + return InputType::InsertLineBreak; + case InsertParagraphSeparator: + case InsertParagraphSeparatorInQuotedContent: + return InputType::InsertParagraph; + default: + return InputType::None; + } } void TypingCommand::typingAddedToOpenCommand(
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h index ecc6a3d..437980a 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -58,33 +58,28 @@ }; typedef unsigned Options; - static void deleteSelection(Document&, EditCommandSource, Options = 0); + static void deleteSelection(Document&, Options = 0); static void deleteKeyPressed(Document&, - EditCommandSource, Options, TextGranularity = CharacterGranularity); static void forwardDeleteKeyPressed(Document&, - EditCommandSource, EditingState*, Options = 0, TextGranularity = CharacterGranularity); static void insertText(Document&, - EditCommandSource, const String&, Options, TextCompositionType = TextCompositionNone, const bool isIncrementalInsertion = false); static void insertText(Document&, - EditCommandSource, const String&, const VisibleSelection&, Options, TextCompositionType = TextCompositionNone, const bool isIncrementalInsertion = false); - static bool insertLineBreak(Document&, EditCommandSource); - static bool insertParagraphSeparator(Document&, EditCommandSource); - static bool insertParagraphSeparatorInQuotedContent(Document&, - EditCommandSource); + static bool insertLineBreak(Document&); + static bool insertParagraphSeparator(Document&); + static bool insertParagraphSeparatorInQuotedContent(Document&); static void closeTyping(LocalFrame*); void insertText(const String& text, bool selectInsertedText, EditingState*); @@ -107,7 +102,8 @@ ETypingCommand commandTypeOfOpenCommand() const { return m_commandType; } TextCompositionType compositionType() const { return m_compositionType; } - // Returns text data of the last added typing. + // |TypingCommand| may contain multiple |InsertTextCommand|, should return + // |textDataForInputEvent()| of the last one. String textDataForInputEvent() const final; private: @@ -159,10 +155,6 @@ LocalFrame*); void updatePreservesTypingStyle(ETypingCommand); - // Returns |false| to cancel adding typing. - bool willAddTypingToOpenCommand(EditCommandSource, - InputEvent::InputType, - const String& text = nullAtom); void typingAddedToOpenCommand(ETypingCommand); bool makeEditableRootEmpty(EditingState*); @@ -174,7 +166,6 @@ ETypingCommand m_commandType; String m_textToInsert; - InputEvent::InputType m_inputType; bool m_openForMoreTyping; bool m_selectInsertedText; bool m_smartDelete;
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommandTest.cpp index 11674a6..f34fa352 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommandTest.cpp +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommandTest.cpp
@@ -50,8 +50,7 @@ .build()); // Inserting line break should not crash or hit assertion. - TypingCommand::insertLineBreak(document(), - EditCommandSource::kMenuOrKeyBinding); + TypingCommand::insertLineBreak(document()); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp index 407f538..c02a63b 100644 --- a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp +++ b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
@@ -187,14 +187,6 @@ didRemoveAllEventHandlers(target); } -void EventHandlerRegistry::didMoveBetweenFrameHosts(EventTarget& target, - FrameHost* oldFrameHost, - FrameHost* newFrameHost) { - ASSERT(newFrameHost != oldFrameHost); - oldFrameHost->eventHandlerRegistry().didMoveOutOfFrameHost(target); - newFrameHost->eventHandlerRegistry().didMoveIntoFrameHost(target); -} - void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target) { for (size_t i = 0; i < EventHandlerClassCount; ++i) { EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
diff --git a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h index 56d7750..94cd9ab 100644 --- a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h +++ b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h
@@ -63,9 +63,6 @@ void didMoveIntoFrameHost(EventTarget&); void didMoveOutOfFrameHost(EventTarget&); - static void didMoveBetweenFrameHosts(EventTarget&, - FrameHost* oldFrameHost, - FrameHost* newFrameHost); // Either |documentDetached| or |didMove{Into,OutOf,Between}FrameHosts| must // be called whenever the FrameHost that is associated with a registered event
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp index 3b9f60c..d5f6e8a 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -4,6 +4,7 @@ #include "core/frame/ImageBitmap.h" +#include "core/html/Float32ImageData.h" #include "core/html/HTMLCanvasElement.h" #include "core/html/HTMLVideoElement.h" #include "core/html/ImageData.h" @@ -757,6 +758,8 @@ resizedPixels.release().leakRef()); } +// TODO(zakerinasab): Fix this and the constructor from Float32ImageData +// when the CL for Float32ImageData landed. ImageBitmap::ImageBitmap(ImageData* data, Optional<IntRect> cropRect, const ImageBitmapOptions& options) { @@ -905,6 +908,10 @@ m_image = StaticBitmapImage::create(std::move(skImage)); } +ImageBitmap::ImageBitmap(Float32ImageData* data, + Optional<IntRect> cropRect, + const ImageBitmapOptions& options) {} + ImageBitmap::ImageBitmap(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options) { @@ -989,6 +996,12 @@ return new ImageBitmap(data, cropRect, options); } +ImageBitmap* ImageBitmap::create(Float32ImageData* data, + Optional<IntRect> cropRect, + const ImageBitmapOptions& options) { + return new ImageBitmap(data, cropRect, options); +} + ImageBitmap* ImageBitmap::create(ImageBitmap* bitmap, Optional<IntRect> cropRect, const ImageBitmapOptions& options) {
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h index 99fd4d5..eab4930 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.h +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -21,6 +21,7 @@ #include <memory> namespace blink { +class Float32ImageData; class HTMLCanvasElement; class HTMLVideoElement; class ImageData; @@ -65,6 +66,9 @@ static ImageBitmap* create(ImageData*, Optional<IntRect>, const ImageBitmapOptions& = ImageBitmapOptions()); + static ImageBitmap* create(Float32ImageData*, + Optional<IntRect>, + const ImageBitmapOptions& = ImageBitmapOptions()); static ImageBitmap* create(ImageBitmap*, Optional<IntRect>, const ImageBitmapOptions& = ImageBitmapOptions()); @@ -150,6 +154,7 @@ ImageBitmap(HTMLCanvasElement*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(OffscreenCanvas*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(ImageData*, Optional<IntRect>, const ImageBitmapOptions&); + ImageBitmap(Float32ImageData*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(ImageBitmap*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(PassRefPtr<StaticBitmapImage>); ImageBitmap(PassRefPtr<StaticBitmapImage>,
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in deleted file mode 100644 index b35509b..0000000 --- a/third_party/WebKit/Source/core/frame/Settings.in +++ /dev/null
@@ -1,435 +0,0 @@ -# Defines properties which are available on the Settings object. -# -# Please think carefully before adding a new Setting. Some questions to -# consider are: -# - Should this be a RuntimeEnabledFeature instead? Settings are for things -# which we support either values of at runtime. Features are set at renderer -# process startup and are never changed. Features also tend to be set to a -# value based on the platform or the stability of the code in question, where -# as settings both codepaths need to be stable. -# - How will you ensure test coverage of all relevant values of your setting? -# - Is the default value appropriate for other platforms or ports which may -# not be aware of your setting? -# - Can your setting result in behavior differences observable to web -# developers? -# - Should this setting ideally be removed in the future? If so please file -# a bug and reference it in the comments for your setting. -# -# One reason to add a Setting is to manage the risk associated with adding a -# new feature. For example, we may choose to ship a new UI behavior or -# performance optimization to ChromeOS users first (in order to gather feedback -# and metrics on its use from the wild) before attempting to ship it to -# Windows. -# -# FIXME: Add support for global settings. -# FIXME: Add support for custom getters/setters. - -defaultTextEncodingName type=String - -# Do not hide chars typed in password fields immediately, but let the last char stay -# visible for N seconds, configured by the passwordEchoDurationInSeconds setting -# FIXME: Enable automatically if passwordEchoDurationInSeconds is set to a positive value. -passwordEchoEnabled initial=false - -# Configure how long the last char should say visible in seconds. -passwordEchoDurationInSeconds type=double, initial=1 - -# Sets the magnification value for validation message timer. If the -# magnification value is N, a validation message disappears automatically after -# <message length> * N / 1000 seconds. If N is equal to or less than 0, a -# validation message doesn't disappears automaticaly. -validationMessageTimerMagnification type=int, initial=50 - -# Number of pixels below which 2D canvas is rendered in software -# even if hardware acceleration is enabled. -# Hardware acceleration is useful for large canvases where it can avoid the -# pixel bandwidth between the CPU and GPU. But GPU acceleration comes at -# a price - extra back-buffer and texture copy. Small canvases are also -# widely used for stylized fonts. Anti-aliasing text in hardware at that -# scale is generally slower. So below a certain size it is better to -# draw canvas in software. -minimumAccelerated2dCanvasSize type=int, initial=257*256 - -minimumFontSize type=int, initial=0, invalidate=Style -minimumLogicalFontSize type=int, initial=0, invalidate=Style -defaultFontSize type=int, initial=0, invalidate=Style -defaultFixedFontSize type=int, initial=0, invalidate=Style - -editingBehaviorType type=EditingBehaviorType, initial=editingBehaviorTypeForPlatform() - -localStorageEnabled initial=false -allowUniversalAccessFromFileURLs initial=true -allowFileAccessFromFileURLs initial=true -javaScriptCanOpenWindowsAutomatically initial=false -supportsMultipleWindows initial=true -javaScriptCanAccessClipboard initial=false -shouldPrintBackgrounds initial=false -shouldClearDocumentBackground initial=true - -textAreasAreResizable initial=false, invalidate=Style -acceleratedCompositingEnabled initial=true, invalidate=AcceleratedCompositing - -offlineWebApplicationCacheEnabled initial=true -allowScriptsToCloseWindows initial=false - -# FIXME: This should really be disabled by default as it makes platforms that -# don't support the feature download files they can't use by. -# Leaving enabled for now to not change existing behavior. -downloadableBinaryFontsEnabled initial=true - -xssAuditorEnabled initial=false - -preferCompositingToLCDTextEnabled initial=false, invalidate=AcceleratedCompositing - -# 3D canvas (WebGL) support. -webGLEnabled initial=false - -webGLErrorsToConsoleEnabled initial=true -antialiased2dCanvasEnabled initial=true -antialiasedClips2dCanvasEnabled initial=true -accelerated2dCanvasMSAASampleCount type=int, initial=0 - -hyperlinkAuditingEnabled initial=false -allowRunningOfInsecureContent initial=true - -mediaControlsOverlayPlayButtonEnabled initial=false -mediaPlaybackRequiresUserGesture initial=false - -# This flags overrides mediaPlaybackRequiresUserGesture -crossOriginMediaPlaybackRequiresUserGesture initial=false - -presentationRequiresUserGesture initial=true - -scrollAnimatorEnabled initial=true - -# Used to disable threaded, compositor scrolling for testing purposes. -# crbug.com/410974 tracks removal once alternative solutions for selective -# main thread scrolling are supported. -threadedScrollingEnabled initial=true, invalidate=Style - -# Used in layout tests for gesture tap highlights. Makes the highlights square -# (rather than rounded) to make it possible to reftest the results. -mockGestureTapHighlightsEnabled initial=false - -shouldRespectImageOrientation initial=false - -# Limited use by features which behave differently depending on the input -# devices available. For example, the pointer and hover media queries. -# Note that we need to be careful when basing behavior or UI on this - -# just because a device is present doesn't mean the user cares about it -# or uses it (i.e. Chromebook Pixel users generally don't want to give up -# screen real estate just because they happen to have a touchscreen). -deviceSupportsTouch initial=false - -# This value indicates the number of simultaneous multi-touch points supported -# by the currently connected screen/digitizer that supports the most points. -# From Pointer Events spec: -# http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints -maxTouchPoints type=int, initial=0 - -# Whether touch gestures should be "fuzzed" to nearest touch targets. -# It's expected that this is enabled everywhere by default, but it may be -# disabled for testing purposes as the algorithm is not yet perfect. -# crbug.com/304895 tracks removal once we're satisfied with the algorithm. -touchAdjustmentEnabled initial=true - -# Determines whether WebViewClient::didTapMultipleTargets will be used for -# touch disambiguation. -multiTargetTapNotificationEnabled initial=true - -syncXHRInDocumentsEnabled initial=true -cookieEnabled initial=true -navigateOnDragDrop initial=true -DOMPasteAllowed initial=false - -allowCustomScrollbarInMainFrame initial=true -webSecurityEnabled initial=true - -# Special keyboard navigation mode intented for platforms with no -# proper mouse or touch support, such as a TV controller with a remote. -spatialNavigationEnabled initial=false - -# This setting adds a means to enable/disable touch initiated drag & drop. If -# enabled, the user can initiate drag using long press. -# crbug.com/304894 tracks removal once it's been enabled on all platforms. -touchDragDropEnabled initial=false - -# Some apps could have a default video poster if it is not set. -defaultVideoPosterURL type=String - -smartInsertDeleteEnabled initial=false -selectTrailingWhitespaceEnabled initial=defaultSelectTrailingWhitespaceEnabled - -selectionIncludesAltImageText initial=false - -selectionStrategy type=SelectionStrategy, initial=SelectionStrategy::Character - -######## Settings used by Android WebView below ######## - -useLegacyBackgroundSizeShorthandBehavior initial=false - -# This quirk is to maintain compatibility with Android apps built on -# the Android SDK prior to and including version 18. -# Presumably, this can be removed any time after 2015. -# See http://crbug.com/282130. -viewportMetaZeroValuesQuirk initial=false - -# Another Android SDK <= 18 quirk, removable 2015. -# See http://crbug.com/295287 -ignoreMainFrameOverflowHiddenQuirk initial=false - -# Yet another Android SDK <= 18 quirk, removable 2015. -# See http://crbug.com/305236 -reportScreenSizeInPhysicalPixelsQuirk initial=false - -# One more Android SDK <= 18 quirk, removable 2015. -# See http://crbug.com/306548 -viewportMetaMergeContentQuirk initial=false - -# This quirk is to maintain compatibility with Android apps. -# It will be possible to remove it once WebSettings.{get|set}UseWideViewPort -# API function will be removed. -# See http://crbug.com/288037. -wideViewportQuirkEnabled initial=false - -# Used by the android_webview to support a horizontal height auto-sizing -# mode. -forceZeroLayoutHeight initial=false, invalidate=ViewportDescription - -mainFrameClipsContent initial=true - -# For android.webkit.WebSettings.setUseWideViewport() -# http://developer.android.com/reference/android/webkit/WebSettings.html#setUseWideViewPort(boolean) -useWideViewport initial=true, invalidate=ViewportDescription - -# For android.webkit.WebSettings.setLoadWithOverviewMode() -# http://developer.android.com/reference/android/webkit/WebSettings.html#setLoadWithOverviewMode(boolean) -loadWithOverviewMode initial=true, invalidate=ViewportDescription - -# Used by android_webview to support legacy apps that inject script into a top-level initial empty -# document and expect it to persist on navigation, even though the origin is unique. Note that this -# behavior violates the requirements described by [Initialising a new Document object] in -# https://html.spec.whatwg.org/multipage/browsers.html#navigating-across-documents. -shouldReuseGlobalForUnownedMainFrame initial=false - -######## End of settings used by Android WebView ######## - - -# Touch based text selection and editing on desktop. -# crbug.com/304873 tracks removal once it's been enabled on all platforms. -touchEditingEnabled initial=false - -# If true, scrollers will use overlay scrollbars. These do not take up any -# layout width, are drawn using solid color quads by the compositor, and fade away -# after a timeout. -useSolidColorScrollbars initial=false - -# Experiment to have all APIs reflect the layout viewport. -# crbug.com/489206 tracks the experiment. -inertVisualViewport initial=false - -# The rubber-band overscroll effect is implemented in Blink and is being moved -# to the compositor thread. This will be set to true and eventually removed. -# crbug.com/133097 -rubberBandingOnCompositorThread initial=false - -# Font scale factor for accessibility, applied as part of text autosizing. -accessibilityFontScaleFactor type=double, initial=1.0, invalidate=TextAutosizing - -# Only used by Layout Tests and inspector emulation. -mediaTypeOverride type=String, initial="", invalidate=MediaQuery -displayModeOverride type=WebDisplayMode, initial=WebDisplayModeUndefined, invalidate=MediaQuery - -# loadsImagesAutomatically only suppresses the network load of -# the image URL. A cached image will still be rendered if requested. -loadsImagesAutomatically initial=false, invalidate=ImageLoading -imagesEnabled initial=true, invalidate=ImageLoading -imageAnimationPolicy type=ImageAnimationPolicy, initial=ImageAnimationPolicyAllowed - -# Number of outstanding and pending tokens allowed in the background HTML -# parser. A value of 0 indicates the parser should use its default value. -backgroundHtmlParserOutstandingTokenLimit type=unsigned, initial=0 -backgroundHtmlParserPendingTokenLimit type=unsigned, initial=0 - -# Html preload scanning is a fast, early scan of HTML documents to find loadable -# resources before the parser advances to them. If it is disabled, resources will -# be loaded later. -doHtmlPreloadScanning initial=true - -pluginsEnabled initial=false - -viewportEnabled initial=false, invalidate=ViewportDescription -viewportMetaEnabled initial=false, invalidate=ViewportDescription - -dnsPrefetchingEnabled initial=false, invalidate=DNSPrefetching - -dataSaverEnabled initial=false - -# FIXME: This is a temporary flag and should be removed -# when squashing is ready. (crbug.com/261605) -layerSquashingEnabled initial=false - -# Clients that execute script should call ScriptController::canExecuteScripts() -# instead of this function. ScriptController::canExecuteScripts() checks the -# HTML sandbox, plugin sandboxing, and other important details. -scriptEnabled initial=false - -# Forces initialization of main world, even if no scripts will be executed. -# Used by inspector to report all contexts. -forceMainWorldInitialization initial=false, invalidate=DOMWorlds - -# Compensates for poor text legibility on mobile devices. This value is -# multiplied by the font scale factor when performing text autosizing of -# websites that do not set an explicit viewport description. -deviceScaleAdjustment type=double, initial=1.0, invalidate=TextAutosizing - -# This value indicates the maximum number of bytes a document is allowed to -# transmit in Beacons (via navigator.sendBeacon()) -- Beacons are intended to be -# smaller payloads transmitted as a page is unloading, not a general (one-way) -# network transmission API. The spec <https://w3c.github.io/beacon/> does not -# proscribe an upper limit, but allows for it -- the underlying API will return -# 'false' in that case. -maxBeaconTransmission type=int, initial=65536 - -# This value is set to false if the platform does not support fullscreen. -# When set to false all the requests to enter fullscreen will return an error -# (fullscreenerror or webkitfullscreenerror) as specified in the standard: -# http://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen -fullscreenSupported initial=true - -# V8 supports different types of caching. Used by V8 bindings. -v8CacheOptions type=V8CacheOptions, initial=V8CacheOptionsDefault - -# V8 code cache for CacheStorage supports three types of strategies (none, normal and aggressive). -v8CacheStrategiesForCacheStorage type=V8CacheStrategiesForCacheStorage, initial=V8CacheStrategiesForCacheStorage::Default - -# These values are bit fields for the properties of available pointing devices -# and may take on multiple values (e.g. laptop with touchpad and touchscreen -# has pointerType coarse *and* fine). -availablePointerTypes type=int, initial=PointerTypeNone, invalidate=MediaQuery -availableHoverTypes type=int, initial=HoverTypeNone, invalidate=MediaQuery - -# These values specify properties of the user's primary pointing device only. -primaryPointerType type=PointerType, initial=PointerTypeNone, invalidate=MediaQuery -primaryHoverType type=HoverType, initial=HoverTypeNone, invalidate=MediaQuery - -# Whether accessibility support is enabled at all. -accessibilityEnabled initial=false, invalidate=AccessibilityState - -# If true, the value in password fields is exposed to assistive technologies. -accessibilityPasswordValuesEnabled initial=false - -# If true, static text nodes expose inline text box children. -inlineTextBoxAccessibilityEnabled initial=false - -# If true, context menu will be shown on mouse up instead of mouse down. -# Typically enabled on Windows to match platform convention. -showContextMenuOnMouseUp initial=false - -# If true, context menu will be shown on any long press event. -# Used on Android to prevent a context menu from being shown in certain situations -# (i.e. long pressing an empty div) -alwaysShowContextMenuOnTouch initial=true - -disableReadingFromCanvas initial=false -strictMixedContentChecking initial=false -strictMixedContentCheckingForPlugin initial=false -strictPowerfulFeatureRestrictions initial=false -strictlyBlockBlockableMixedContent initial=false -allowGeolocationOnInsecureOrigins initial=false -logDnsPrefetchAndPreconnect initial=false -logPreload initial=false - -# These values specify the UA intial viewport style. -# It is dynamically set by the inspector for mobile emulation and can be -# used by content embedders to specify custom style on certain platforms. -viewportStyle type=WebViewportStyle, initial=WebViewportStyle::Default, invalidate=ViewportRule - -# Automatic track selection is performed based on user preference for track kind specified -# by this setting. -textTrackKindUserPreference type=TextTrackKindUserPreference, initial=TextTrackKindUserPreference::Default, invalidate=TextTrackKindUserPreference - -# User style overrides for captions and subtitles -textTrackBackgroundColor type=String -textTrackFontFamily type=String -textTrackFontStyle type=String -textTrackFontVariant type=String -textTrackTextColor type=String -textTrackTextShadow type=String -textTrackTextSize type=String - -# Margin for title-safe placement of cues with overscan, gives top and bottom margin size as -# percentage of video element height (for horizontal text) into which cues will not be placed. -textTrackMarginPercentage type=double, initial=0 - -lowPriorityIframes initial=false - -progressBarCompletion type=ProgressBarCompletion, initial=ProgressBarCompletion::LoadEvent - -historyEntryRequiresUserGesture initial=false - -# Do we want to try to save screen real estate in the media player by hiding -# the volume slider / mute button? -preferHiddenVolumeControls initial=false - -# Whether to disallow network fetches for parser blocking scripts in the main -# frame inserted via document.write, for users on 2G or connections that are -# effectively 2G. -disallowFetchForDocWrittenScriptsInMainFrameIfEffectively2G initial=false - -# Whether to disallow network fetches for parser blocking scripts in the main -# frame inserted via document.write, for users on slow connections. -disallowFetchForDocWrittenScriptsInMainFrameOnSlowConnections initial=false - -# Whether to disallow network fetches for parser blocking scripts in the main -# frame inserted via document.write, regardless of connection type. -disallowFetchForDocWrittenScriptsInMainFrame initial=false - -# Whether to invalidate device-dependent media queries and restore scroll positions -# on frame resize assuming device rotation. -mainFrameResizesAreOrientationChanges initial=false - -# Ability to override the default 'passive' value in AddEventListenerOptions. This -# is useful to demonstrate the power of passive event listeners. This can be removed -# when there is greater adoption, interventions to force it on and associated devtools -# to enable it have been shipped. -passiveListenerDefault type=PassiveListenerDefault, initial=PassiveListenerDefault::False - -# Use default interpolation quality to scale bitmap images if quality is not determined -# in other ways. This can help us writing reftests containing scaled images. -useDefaultImageInterpolationQuality initial=false - -# Variant of the ParseHTMLOnMainThread experiment. One experiment immediately -# tokenizes input bytes. The default is to tokenize with a post task. -parseHTMLOnMainThreadSyncTokenize initial=false - -# Variant of the ParseHTMLOnMainThread experiment. This is designed to coalesce -# TokenizedChunks when the experiment is running in threaded mode. -parseHTMLOnMainThreadCoalesceChunks initial=false - -# Whether the CSSPreloadScanner is used for externally CSS preloads. NoPreload -# indicates that the scanner will be used, but no preloads issued. -cssExternalScannerNoPreload initial=false -cssExternalScannerPreload initial=false - -browserSideNavigationEnabled initial=false - -# Some platforms have media subsystems which are too buggy to allow preloading -# of content by default. See http://crbug.com/612909 for details. -forcePreloadNoneForMediaElements initial=false - -hideScrollbars initial=false - -# Spellchecking is enabled by default for elements that do not specify it explicitly -# using the "spellcheck" attribute. -spellCheckEnabledByDefault initial=true - -# Whether download UI should be hidden for the current page content. -hideDownloadUI initial=false - -# Whether or not to issue range requests for images and show placeholders. -fetchImagePlaceholders initial=false - -# Whether the frame is a presentation receiver and should expose -# `navigator.presentation.receiver`. -presentationReceiver initial=false
diff --git a/third_party/WebKit/Source/core/frame/Settings.json5 b/third_party/WebKit/Source/core/frame/Settings.json5 new file mode 100644 index 0000000..7be353a --- /dev/null +++ b/third_party/WebKit/Source/core/frame/Settings.json5
@@ -0,0 +1,932 @@ +{ +// Defines properties which are available on the Settings object. +// +// Please think carefully before adding a new Setting. Some questions to +// consider are: +// - Should this be a RuntimeEnabledFeature instead? Settings are for things +// which we support either values of at runtime. Features are set at renderer +// process startup and are never changed. Features also tend to be set to a +// value based on the platform or the stability of the code in question, where +// as settings both codepaths need to be stable. +// - How will you ensure test coverage of all relevant values of your setting? +// - Is the default value appropriate for other platforms or ports which may +// not be aware of your setting? +// - Can your setting result in behavior differences observable to web +// developers? +// - Should this setting ideally be removed in the future? If so please file +// a bug and reference it in the comments for your setting. +// +// One reason to add a Setting is to manage the risk associated with adding a +// new feature. For example, we may choose to ship a new UI behavior or +// performance optimization to ChromeOS users first (in order to gather feedback +// and metrics on its use from the wild) before attempting to ship it to +// Windows. +// +// FIXME: Add support for global settings. +// FIXME: Add support for custom getters/setters. + +// Valid parameters for data entries below. +parameters: { + type: { + default: "bool" + }, + initial: {}, + invalidate: {}, +}, + +data: [ + { + name: "defaultTextEncodingName", + type: "String", + }, + + // Do not hide chars typed in password fields immediately, but let the last char stay + // visible for N seconds, configured by the passwordEchoDurationInSeconds setting + // FIXME: Enable automatically if passwordEchoDurationInSeconds is set to a positive value. + { + name: "passwordEchoEnabled", + initial: false, + }, + + // Configure how long the last char should say visible in seconds. + { + name: "passwordEchoDurationInSeconds", + initial: 1, + type: "double", + }, + + // Sets the magnification value for validation message timer. If the + // magnification value is N, a validation message disappears automatically after + // <message length> * N / 1000 seconds. If N is equal to or less than 0, a + // validation message doesn't disappears automaticaly. + { + name: "validationMessageTimerMagnification", + initial: 50, + type: "int", + }, + + // Number of pixels below which 2D canvas is rendered in software + // even if hardware acceleration is enabled. + // Hardware acceleration is useful for large canvases where it can avoid the + // pixel bandwidth between the CPU and GPU. But GPU acceleration comes at + // a price - extra back-buffer and texture copy. Small canvases are also + // widely used for stylized fonts. Anti-aliasing text in hardware at that + // scale is generally slower. So below a certain size it is better to + // draw canvas in software. + { + name: "minimumAccelerated2dCanvasSize", + initial: "257*256", + type: "int", + }, + + { + name: "minimumFontSize", + initial: 0, + invalidate: "Style", + type: "int", + }, + { + name: "minimumLogicalFontSize", + initial: 0, + invalidate: "Style", + type: "int", + }, + { + name: "defaultFontSize", + initial: 0, + invalidate: "Style", + type: "int", + }, + { + name: "defaultFixedFontSize", + initial: 0, + invalidate: "Style", + type: "int", + }, + + { + name: "editingBehaviorType", + initial: "editingBehaviorTypeForPlatform()", + type: "EditingBehaviorType", + }, + + { + name: "localStorageEnabled", + initial: false, + }, + { + name: "allowUniversalAccessFromFileURLs", + initial: true, + }, + { + name: "allowFileAccessFromFileURLs", + initial: true, + }, + { + name: "javaScriptCanOpenWindowsAutomatically", + initial: false, + }, + { + name: "supportsMultipleWindows", + initial: true, + }, + { + name: "javaScriptCanAccessClipboard", + initial: false, + }, + { + name: "shouldPrintBackgrounds", + initial: false, + }, + { + name: "shouldClearDocumentBackground", + initial: true, + }, + + { + name: "textAreasAreResizable", + initial: false, + invalidate: "Style", + }, + { + name: "acceleratedCompositingEnabled", + initial: true, + invalidate: "AcceleratedCompositing", + }, + + { + name: "offlineWebApplicationCacheEnabled", + initial: true, + }, + { + name: "allowScriptsToCloseWindows", + initial: false, + }, + + // FIXME: This should really be disabled by default as it makes platforms that + // don't support the feature download files they can't use by. + // Leaving enabled for now to not change existing behavior. + { + name: "downloadableBinaryFontsEnabled", + initial: true, + }, + + { + name: "xssAuditorEnabled", + initial: false, + }, + + { + name: "preferCompositingToLCDTextEnabled", + initial: false, + invalidate: "AcceleratedCompositing", + }, + + // 3D canvas (WebGL) support. + { + name: "webGLEnabled", + initial: false, + }, + + { + name: "webGLErrorsToConsoleEnabled", + initial: true, + }, + { + name: "antialiased2dCanvasEnabled", + initial: true, + }, + { + name: "antialiasedClips2dCanvasEnabled", + initial: true, + }, + { + name: "accelerated2dCanvasMSAASampleCount", + initial: 0, + type: "int", + }, + + { + name: "hyperlinkAuditingEnabled", + initial: false, + }, + { + name: "allowRunningOfInsecureContent", + initial: true, + }, + + { + name: "mediaControlsOverlayPlayButtonEnabled", + initial: false, + }, + { + name: "mediaPlaybackRequiresUserGesture", + initial: false, + }, + + // This flags overrides mediaPlaybackRequiresUserGesture + { + name: "crossOriginMediaPlaybackRequiresUserGesture", + initial: false, + }, + + { + name: "presentationRequiresUserGesture", + initial: true, + }, + + { + name: "scrollAnimatorEnabled", + initial: true, + }, + + // Used to disable threaded, compositor scrolling for testing purposes. + // crbug.com/410974 tracks removal once alternative solutions for selective + // main thread scrolling are supported. + { + name: "threadedScrollingEnabled", + initial: true, + invalidate: "Style", + }, + + // Used in layout tests for gesture tap highlights. Makes the highlights square + // (rather than rounded) to make it possible to reftest the results. + { + name: "mockGestureTapHighlightsEnabled", + initial: false, + }, + + { + name: "shouldRespectImageOrientation", + initial: false, + }, + + // Limited use by features which behave differently depending on the input + // devices available. For example, the pointer and hover media queries. + // Note that we need to be careful when basing behavior or UI on this - + // just because a device is present doesn't mean the user cares about it + // or uses it (i.e. Chromebook Pixel users generally don't want to give up + // screen real estate just because they happen to have a touchscreen). + { + name: "deviceSupportsTouch", + initial: false, + }, + + // This value indicates the number of simultaneous multi-touch points supported + // by the currently connected screen/digitizer that supports the most points. + // From Pointer Events spec: + // http://www.w3.org/TR/pointerevents///widl-Navigator-maxTouchPoints + { + name: "maxTouchPoints", + initial: 0, + type: "int", + }, + + // Whether touch gestures should be "fuzzed" to nearest touch targets. + // It's expected that this is enabled everywhere by default, but it may be + // disabled for testing purposes as the algorithm is not yet perfect. + // crbug.com/304895 tracks removal once we're satisfied with the algorithm. + { + name: "touchAdjustmentEnabled", + initial: true, + }, + + // Determines whether WebViewClient::didTapMultipleTargets will be used for + // touch disambiguation. + { + name: "multiTargetTapNotificationEnabled", + initial: true, + }, + + { + name: "syncXHRInDocumentsEnabled", + initial: true, + }, + { + name: "cookieEnabled", + initial: true, + }, + { + name: "navigateOnDragDrop", + initial: true, + }, + { + name: "DOMPasteAllowed", + initial: false, + }, + + { + name: "allowCustomScrollbarInMainFrame", + initial: true, + }, + { + name: "webSecurityEnabled", + initial: true, + }, + + // Special keyboard navigation mode intented for platforms with no + // proper mouse or touch support, such as a TV controller with a remote. + { + name: "spatialNavigationEnabled", + initial: false, + }, + + // This setting adds a means to enable/disable touch initiated drag & drop. If + // enabled, the user can initiate drag using long press. + // crbug.com/304894 tracks removal once it's been enabled on all platforms. + { + name: "touchDragDropEnabled", + initial: false, + }, + + // Some apps could have a default video poster if it is not set. + { + name: "defaultVideoPosterURL", + type: "String", + }, + + { + name: "smartInsertDeleteEnabled", + initial: false, + }, + { + name: "selectTrailingWhitespaceEnabled", + initial: "defaultSelectTrailingWhitespaceEnabled", + }, + + { + name: "selectionIncludesAltImageText", + initial: false, + }, + + { + name: "selectionStrategy", + initial: "SelectionStrategy::Character", + type: "SelectionStrategy", + }, + + //////////////// Settings used by Android WebView below //////////////// + + { + name: "useLegacyBackgroundSizeShorthandBehavior", + initial: false, + }, + + // This quirk is to maintain compatibility with Android apps built on + // the Android SDK prior to and including version 18. + // Presumably, this can be removed any time after 2015. + // See http://crbug.com/282130. + { + name: "viewportMetaZeroValuesQuirk", + initial: false, + }, + + // Another Android SDK <= 18 quirk, removable 2015. + // See http://crbug.com/295287 + { + name: "ignoreMainFrameOverflowHiddenQuirk", + initial: false, + }, + + // Yet another Android SDK <= 18 quirk, removable 2015. + // See http://crbug.com/305236 + { + name: "reportScreenSizeInPhysicalPixelsQuirk", + initial: false, + }, + + // One more Android SDK <= 18 quirk, removable 2015. + // See http://crbug.com/306548 + { + name: "viewportMetaMergeContentQuirk", + initial: false, + }, + + // This quirk is to maintain compatibility with Android apps. + // It will be possible to remove it once WebSettings.{get|set}UseWideViewPort + // API function will be removed. + // See http://crbug.com/288037. + { + name: "wideViewportQuirkEnabled", + initial: false, + }, + + // Used by the android_webview to support a horizontal height auto-sizing + // mode. + { + name: "forceZeroLayoutHeight", + initial: false, + invalidate: "ViewportDescription", + }, + + { + name: "mainFrameClipsContent", + initial: true, + }, + + // For android.webkit.WebSettings.setUseWideViewport() + // http://developer.android.com/reference/android/webkit/WebSettings.html//setUseWideViewPort(boolean) + { + name: "useWideViewport", + initial: true, + invalidate: "ViewportDescription", + }, + + // For android.webkit.WebSettings.setLoadWithOverviewMode() + // http://developer.android.com/reference/android/webkit/WebSettings.html//setLoadWithOverviewMode(boolean) + { + name: "loadWithOverviewMode", + initial: true, + invalidate: "ViewportDescription", + }, + + // Used by android_webview to support legacy apps that inject script into a top-level initial empty + // document and expect it to persist on navigation, even though the origin is unique. Note that this + // behavior violates the requirements described by [Initialising a new Document object] in + // https://html.spec.whatwg.org/multipage/browsers.html//navigating-across-documents. + { + name: "shouldReuseGlobalForUnownedMainFrame", + initial: false, + }, + + //////////////// End of settings used by Android WebView //////////////// + + + // Touch based text selection and editing on desktop. + // crbug.com/304873 tracks removal once it's been enabled on all platforms. + { + name: "touchEditingEnabled", + initial: false, + }, + + // If true, scrollers will use overlay scrollbars. These do not take up any + // layout width, are drawn using solid color quads by the compositor, and fade away + // after a timeout. + { + name: "useSolidColorScrollbars", + initial: false, + }, + + // Experiment to have all APIs reflect the layout viewport. + // crbug.com/489206 tracks the experiment. + { + name: "inertVisualViewport", + initial: false, + }, + + // The rubber-band overscroll effect is implemented in Blink and is being moved + // to the compositor thread. This will be set to true and eventually removed. + // crbug.com/133097 + { + name: "rubberBandingOnCompositorThread", + initial: false, + }, + + // Font scale factor for accessibility, applied as part of text autosizing. + { + name: "accessibilityFontScaleFactor", + initial: "1.0", + invalidate: "TextAutosizing", + type: "double", + }, + + // Only used by Layout Tests and inspector emulation. + { + name: "mediaTypeOverride", + initial: "\"\"", + invalidate: "MediaQuery", + type: "String", + }, + { + name: "displayModeOverride", + initial: "WebDisplayModeUndefined", + invalidate: "MediaQuery", + type: "WebDisplayMode", + }, + + // loadsImagesAutomatically only suppresses the network load of + // the image URL. A cached image will still be rendered if requested. + { + name: "loadsImagesAutomatically", + initial: false, + invalidate: "ImageLoading", + }, + { + name: "imagesEnabled", + initial: true, + invalidate: "ImageLoading", + }, + { + name: "imageAnimationPolicy", + initial: "ImageAnimationPolicyAllowed", + type: "ImageAnimationPolicy", + }, + + // Number of outstanding and pending tokens allowed in the background HTML + // parser. A value of 0 indicates the parser should use its default value. + { + name: "backgroundHtmlParserOutstandingTokenLimit", + initial: 0, + type: "unsigned", + }, + { + name: "backgroundHtmlParserPendingTokenLimit", + initial: 0, + type: "unsigned", + }, + + // Html preload scanning is a fast, early scan of HTML documents to find loadable + // resources before the parser advances to them. If it is disabled, resources will + // be loaded later. + { + name: "doHtmlPreloadScanning", + initial: true, + }, + + { + name: "pluginsEnabled", + initial: false, + }, + + { + name: "viewportEnabled", + initial: false, + invalidate: "ViewportDescription", + }, + { + name: "viewportMetaEnabled", + initial: false, + invalidate: "ViewportDescription", + }, + + { + name: "dnsPrefetchingEnabled", + initial: false, + invalidate: "DNSPrefetching", + }, + + { + name: "dataSaverEnabled", + initial: false, + }, + + // FIXME: This is a temporary flag and should be removed + // when squashing is ready. (crbug.com/261605) + { + name: "layerSquashingEnabled", + initial: false, + }, + + // Clients that execute script should call ScriptController::canExecuteScripts() + // instead of this function. ScriptController::canExecuteScripts() checks the + // HTML sandbox, plugin sandboxing, and other important details. + { + name: "scriptEnabled", + initial: false, + }, + + // Forces initialization of main world, even if no scripts will be executed. + // Used by inspector to report all contexts. + { + name: "forceMainWorldInitialization", + initial: false, + invalidate: "DOMWorlds", + }, + + // Compensates for poor text legibility on mobile devices. This value is + // multiplied by the font scale factor when performing text autosizing of + // websites that do not set an explicit viewport description. + { + name: "deviceScaleAdjustment", + initial: "1.0", + invalidate: "TextAutosizing", + type: "double", + }, + + // This value indicates the maximum number of bytes a document is allowed to + // transmit in Beacons (via navigator.sendBeacon()) -- Beacons are intended to be + // smaller payloads transmitted as a page is unloading, not a general (one-way) + // network transmission API. The spec <https://w3c.github.io/beacon/> does not + // proscribe an upper limit, but allows for it -- the underlying API will return + // 'false' in that case. + { + name: "maxBeaconTransmission", + initial: 65536, + type: "int", + }, + + // This value is set to false if the platform does not support fullscreen. + // When set to false all the requests to enter fullscreen will return an error + // (fullscreenerror or webkitfullscreenerror) as specified in the standard: + // http://fullscreen.spec.whatwg.org///dom-element-requestfullscreen + { + name: "fullscreenSupported", + initial: true, + }, + + // V8 supports different types of caching. Used by V8 bindings. + { + name: "v8CacheOptions", + initial: "V8CacheOptionsDefault", + type: "V8CacheOptions", + }, + + // V8 code cache for CacheStorage supports three types of strategies (none, normal and aggressive). + { + name: "v8CacheStrategiesForCacheStorage", + initial: "V8CacheStrategiesForCacheStorage::Default", + type: "V8CacheStrategiesForCacheStorage", + }, + + // These values are bit fields for the properties of available pointing devices + // and may take on multiple values (e.g. laptop with touchpad and touchscreen + // has pointerType coarse *and* fine). + { + name: "availablePointerTypes", + initial: "PointerTypeNone", + invalidate: "MediaQuery", + type: "int", + }, + { + name: "availableHoverTypes", + initial: "HoverTypeNone", + invalidate: "MediaQuery", + type: "int", + }, + + // These values specify properties of the user's primary pointing device only. + { + name: "primaryPointerType", + initial: "PointerTypeNone", + invalidate: "MediaQuery", + type: "PointerType", + }, + { + name: "primaryHoverType", + initial: "HoverTypeNone", + invalidate: "MediaQuery", + type: "HoverType", + }, + + // Whether accessibility support is enabled at all. + { + name: "accessibilityEnabled", + initial: false, + invalidate: "AccessibilityState", + }, + + // If true, the value in password fields is exposed to assistive technologies. + { + name: "accessibilityPasswordValuesEnabled", + initial: false, + }, + + // If true, static text nodes expose inline text box children. + { + name: "inlineTextBoxAccessibilityEnabled", + initial: false, + }, + + // If true, context menu will be shown on mouse up instead of mouse down. + // Typically enabled on Windows to match platform convention. + { + name: "showContextMenuOnMouseUp", + initial: false, + }, + + // If true, context menu will be shown on any long press event. + // Used on Android to prevent a context menu from being shown in certain situations + // (i.e. long pressing an empty div) + { + name: "alwaysShowContextMenuOnTouch", + initial: true, + }, + + { + name: "disableReadingFromCanvas", + initial: false, + }, + { + name: "strictMixedContentChecking", + initial: false, + }, + { + name: "strictMixedContentCheckingForPlugin", + initial: false, + }, + { + name: "strictPowerfulFeatureRestrictions", + initial: false, + }, + { + name: "strictlyBlockBlockableMixedContent", + initial: false, + }, + { + name: "allowGeolocationOnInsecureOrigins", + initial: false, + }, + { + name: "logDnsPrefetchAndPreconnect", + initial: false, + }, + { + name: "logPreload", + initial: false, + }, + + // These values specify the UA intial viewport style. + // It is dynamically set by the inspector for mobile emulation and can be + // used by content embedders to specify custom style on certain platforms. + { + name: "viewportStyle", + initial: "WebViewportStyle::Default", + invalidate: "ViewportRule", + type: "WebViewportStyle", + }, + + // Automatic track selection is performed based on user preference for track kind specified + // by this setting. + { + name: "textTrackKindUserPreference", + initial: "TextTrackKindUserPreference::Default", + invalidate: "TextTrackKindUserPreference", + type: "TextTrackKindUserPreference", + }, + + // User style overrides for captions and subtitles + { + name: "textTrackBackgroundColor", + type: "String", + }, + { + name: "textTrackFontFamily", + type: "String", + }, + { + name: "textTrackFontStyle", + type: "String", + }, + { + name: "textTrackFontVariant", + type: "String", + }, + { + name: "textTrackTextColor", + type: "String", + }, + { + name: "textTrackTextShadow", + type: "String", + }, + { + name: "textTrackTextSize", + type: "String", + }, + + // Margin for title-safe placement of cues with overscan, gives top and bottom margin size as + // percentage of video element height (for horizontal text) into which cues will not be placed. + { + name: "textTrackMarginPercentage", + initial: 0, + type: "double", + }, + + { + name: "lowPriorityIframes", + initial: false, + }, + + { + name: "progressBarCompletion", + initial: "ProgressBarCompletion::LoadEvent", + type: "ProgressBarCompletion", + }, + + { + name: "historyEntryRequiresUserGesture", + initial: false, + }, + + // Do we want to try to save screen real estate in the media player by hiding + // the volume slider / mute button? + { + name: "preferHiddenVolumeControls", + initial: false, + }, + + // Whether to disallow network fetches for parser blocking scripts in the main + // frame inserted via document.write, for users on 2G or connections that are + // effectively 2G. + { + name: "disallowFetchForDocWrittenScriptsInMainFrameIfEffectively2G", + initial: false, + }, + + // Whether to disallow network fetches for parser blocking scripts in the main + // frame inserted via document.write, for users on slow connections. + { + name: "disallowFetchForDocWrittenScriptsInMainFrameOnSlowConnections", + initial: false, + }, + + // Whether to disallow network fetches for parser blocking scripts in the main + // frame inserted via document.write, regardless of connection type. + { + name: "disallowFetchForDocWrittenScriptsInMainFrame", + initial: false, + }, + + // Whether to invalidate device-dependent media queries and restore scroll positions + // on frame resize assuming device rotation. + { + name: "mainFrameResizesAreOrientationChanges", + initial: false, + }, + + // Ability to override the default 'passive' value in AddEventListenerOptions. This + // is useful to demonstrate the power of passive event listeners. This can be removed + // when there is greater adoption, interventions to force it on and associated devtools + // to enable it have been shipped. + { + name: "passiveListenerDefault", + initial: "PassiveListenerDefault::False", + type: "PassiveListenerDefault", + }, + + // Use default interpolation quality to scale bitmap images if quality is not determined + // in other ways. This can help us writing reftests containing scaled images. + { + name: "useDefaultImageInterpolationQuality", + initial: false, + }, + + // Variant of the ParseHTMLOnMainThread experiment. One experiment immediately + // tokenizes input bytes. The default is to tokenize with a post task. + { + name: "parseHTMLOnMainThreadSyncTokenize", + initial: false, + }, + + // Variant of the ParseHTMLOnMainThread experiment. This is designed to coalesce + // TokenizedChunks when the experiment is running in threaded mode. + { + name: "parseHTMLOnMainThreadCoalesceChunks", + initial: false, + }, + + // Whether the CSSPreloadScanner is used for externally CSS preloads. NoPreload + // indicates that the scanner will be used, but no preloads issued. + { + name: "cssExternalScannerNoPreload", + initial: false, + }, + { + name: "cssExternalScannerPreload", + initial: false, + }, + + { + name: "browserSideNavigationEnabled", + initial: false, + }, + + // Some platforms have media subsystems which are too buggy to allow preloading + // of content by default. See http://crbug.com/612909 for details. + { + name: "forcePreloadNoneForMediaElements", + initial: false, + }, + + { + name: "hideScrollbars", + initial: false, + }, + + // Spellchecking is enabled by default for elements that do not specify it explicitly + // using the "spellcheck" attribute. + { + name: "spellCheckEnabledByDefault", + initial: true, + }, + + // Whether download UI should be hidden for the current page content. + { + name: "hideDownloadUI", + initial: false, + }, + + // Whether or not to issue range requests for images and show placeholders. + { + name: "fetchImagePlaceholders", + initial: false, + }, + + // Whether the frame is a presentation receiver and should expose + // `navigator.presentation.receiver`. + { + name: "presentationReceiver", + initial: false, + }, +] +}
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn index 63cfdfcb..0fab038 100644 --- a/third_party/WebKit/Source/core/html/BUILD.gn +++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -17,6 +17,8 @@ "CrossOriginAttribute.h", "DocumentNameCollection.cpp", "DocumentNameCollection.h", + "Float32ImageData.cpp", + "Float32ImageData.h", "FormAssociated.h", "FormData.cpp", "FormData.h",
diff --git a/third_party/WebKit/Source/core/html/Float32ImageData.cpp b/third_party/WebKit/Source/core/html/Float32ImageData.cpp new file mode 100644 index 0000000..544e19e4 --- /dev/null +++ b/third_party/WebKit/Source/core/html/Float32ImageData.cpp
@@ -0,0 +1,173 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/html/Float32ImageData.h" + +#include "bindings/core/v8/ExceptionState.h" +#include "bindings/core/v8/V8Float32Array.h" +#include "core/dom/ExceptionCode.h" +#include "core/frame/ImageBitmap.h" +#include "core/imagebitmap/ImageBitmapOptions.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "wtf/CheckedNumeric.h" + +namespace blink { + +bool Float32ImageData::validateConstructorArguments( + const unsigned& paramFlags, + const IntSize* size, + const unsigned& width, + const unsigned& height, + const DOMFloat32Array* data, + const String* colorSpace, + ExceptionState* exceptionState) { + return ImageData::validateConstructorArguments( + paramFlags, size, width, height, data, colorSpace, exceptionState, + kFloat32ImageData); +} + +DOMFloat32Array* Float32ImageData::allocateAndValidateFloat32Array( + const unsigned& length, + ExceptionState* exceptionState) { + if (!length) + return nullptr; + DOMFloat32Array* dataArray = DOMFloat32Array::createOrNull(length); + if (!dataArray || length != dataArray->length()) { + if (exceptionState) { + exceptionState->throwDOMException( + V8RangeError, "Out of memory at Float32ImageData creation"); + } + return nullptr; + } + return dataArray; +} + +Float32ImageData* Float32ImageData::create(const IntSize& size) { + if (!Float32ImageData::validateConstructorArguments(kParamSize, &size)) + return nullptr; + DOMFloat32Array* dataArray = + Float32ImageData::allocateAndValidateFloat32Array(4 * size.width() * + size.height()); + return dataArray ? new Float32ImageData(size, dataArray) : nullptr; +} + +Float32ImageData* Float32ImageData::create(const IntSize& size, + DOMFloat32Array* dataArray) { + if (!Float32ImageData::validateConstructorArguments(kParamSize | kParamData, + &size, 0, 0, dataArray)) + return nullptr; + return new Float32ImageData(size, dataArray); +} + +Float32ImageData* Float32ImageData::create(unsigned width, + unsigned height, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments( + kParamWidth | kParamHeight, nullptr, width, height, nullptr, nullptr, + &exceptionState)) + return nullptr; + DOMFloat32Array* dataArray = + Float32ImageData::allocateAndValidateFloat32Array(4 * width * height, + &exceptionState); + return dataArray ? new Float32ImageData(IntSize(width, height), dataArray) + : nullptr; +} + +Float32ImageData* Float32ImageData::create(DOMFloat32Array* data, + unsigned width, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments(kParamData | kParamWidth, + nullptr, width, 0, data, + nullptr, &exceptionState)) + return nullptr; + unsigned height = data->length() / (width * 4); + return new Float32ImageData(IntSize(width, height), data); +} + +Float32ImageData* Float32ImageData::create(DOMFloat32Array* data, + unsigned width, + unsigned height, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamHeight, nullptr, width, height, data, + nullptr, &exceptionState)) + return nullptr; + return new Float32ImageData(IntSize(width, height), data); +} + +Float32ImageData* Float32ImageData::create(unsigned width, + unsigned height, + String colorSpace, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments( + kParamWidth | kParamHeight | kParamColorSpace, nullptr, width, height, + nullptr, &colorSpace, &exceptionState)) + return nullptr; + + DOMFloat32Array* dataArray = + Float32ImageData::allocateAndValidateFloat32Array(4 * width * height, + &exceptionState); + return dataArray ? new Float32ImageData(IntSize(width, height), dataArray, + colorSpace) + : nullptr; +} + +Float32ImageData* Float32ImageData::create(DOMFloat32Array* data, + unsigned width, + String colorSpace, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamColorSpace, nullptr, width, 0, data, + &colorSpace, &exceptionState)) + return nullptr; + unsigned height = data->length() / (width * 4); + return new Float32ImageData(IntSize(width, height), data, colorSpace); +} + +Float32ImageData* Float32ImageData::create(DOMFloat32Array* data, + unsigned width, + unsigned height, + String colorSpace, + ExceptionState& exceptionState) { + if (!Float32ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamHeight | kParamColorSpace, nullptr, + width, height, data, &colorSpace, &exceptionState)) + return nullptr; + return new Float32ImageData(IntSize(width, height), data, colorSpace); +} + +v8::Local<v8::Object> Float32ImageData::associateWithWrapper( + v8::Isolate* isolate, + const WrapperTypeInfo* wrapperType, + v8::Local<v8::Object> wrapper) { + wrapper = + ScriptWrappable::associateWithWrapper(isolate, wrapperType, wrapper); + + if (!wrapper.IsEmpty() && m_data.get()) { + // Create a V8 Float32Array object and set the "data" property + // of the Float32ImageData object to the created v8 object, eliminating the + // C++ callback when accessing the "data" property. + v8::Local<v8::Value> pixelArray = ToV8(m_data.get(), wrapper, isolate); + if (pixelArray.IsEmpty() || + !v8CallBoolean(wrapper->DefineOwnProperty( + isolate->GetCurrentContext(), v8AtomicString(isolate, "data"), + pixelArray, v8::ReadOnly))) + return v8::Local<v8::Object>(); + } + return wrapper; +} + +Float32ImageData::Float32ImageData(const IntSize& size, + DOMFloat32Array* dataArray, + String colorSpaceName) + : m_size(size), + m_colorSpace(ImageData::getImageDataColorSpace(colorSpaceName)), + m_data(dataArray) { + DCHECK_GE(size.width(), 0); + DCHECK_GE(size.height(), 0); + SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= + m_data->length()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/Float32ImageData.h b/third_party/WebKit/Source/core/html/Float32ImageData.h new file mode 100644 index 0000000..73a6b904 --- /dev/null +++ b/third_party/WebKit/Source/core/html/Float32ImageData.h
@@ -0,0 +1,96 @@ +// 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 Float32ImageData_h +#define Float32ImageData_h + +#include "bindings/core/v8/ScriptWrappable.h" +#include "core/CoreExport.h" +#include "core/dom/DOMTypedArray.h" +#include "core/html/ImageData.h" +#include "core/imagebitmap/ImageBitmapSource.h" +#include "platform/geometry/IntRect.h" +#include "platform/geometry/IntSize.h" +#include "platform/heap/Handle.h" +#include "wtf/Compiler.h" +#include "wtf/text/WTFString.h" + +namespace blink { + +class ExceptionState; + +class CORE_EXPORT Float32ImageData final + : public GarbageCollectedFinalized<Float32ImageData>, + public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + static Float32ImageData* create(const IntSize&); + static Float32ImageData* create(const IntSize&, DOMFloat32Array*); + static Float32ImageData* create(unsigned width, + unsigned height, + ExceptionState&); + static Float32ImageData* create(unsigned width, + unsigned height, + String colorSpace, + ExceptionState&); + static Float32ImageData* create(DOMFloat32Array*, + unsigned width, + ExceptionState&); + static Float32ImageData* create(DOMFloat32Array*, + unsigned width, + String colorSpace, + ExceptionState&); + static Float32ImageData* create(DOMFloat32Array*, + unsigned width, + unsigned height, + ExceptionState&); + static Float32ImageData* create(DOMFloat32Array*, + unsigned width, + unsigned height, + String colorSpace, + ExceptionState&); + + IntSize size() const { return m_size; } + int width() const { return m_size.width(); } + int height() const { return m_size.height(); } + String colorSpace() const { + return ImageData::getImageDataColorSpaceName(m_colorSpace); + } + ImageDataColorSpace imageDataColorSpace() { return m_colorSpace; } + const DOMFloat32Array* data() const { return m_data.get(); } + DOMFloat32Array* data() { return m_data.get(); } + + DEFINE_INLINE_TRACE() { visitor->trace(m_data); } + + WARN_UNUSED_RESULT v8::Local<v8::Object> associateWithWrapper( + v8::Isolate*, + const WrapperTypeInfo*, + v8::Local<v8::Object> wrapper) override; + + private: + Float32ImageData(const IntSize&, + DOMFloat32Array*, + String = kLinearRGBImageDataColorSpaceName); + + IntSize m_size; + ImageDataColorSpace m_colorSpace; + Member<DOMFloat32Array> m_data; + + static bool validateConstructorArguments(const unsigned&, + const IntSize* = nullptr, + const unsigned& = 0, + const unsigned& = 0, + const DOMFloat32Array* = nullptr, + const String* = nullptr, + ExceptionState* = nullptr); + + static DOMFloat32Array* allocateAndValidateFloat32Array( + const unsigned&, + ExceptionState* = nullptr); +}; + +} // namespace blink + +#endif // Float32ImageData_h
diff --git a/third_party/WebKit/Source/core/html/Float32ImageData.idl b/third_party/WebKit/Source/core/html/Float32ImageData.idl new file mode 100644 index 0000000..9446a3c --- /dev/null +++ b/third_party/WebKit/Source/core/html/Float32ImageData.idl
@@ -0,0 +1,22 @@ +// 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. + +// https://github.com/junov/CanvasColorSpace/blob/master/CanvasColorSpaceProposal.md#imagedata + +[ + Constructor(unsigned long sw, unsigned long sh), + Constructor(unsigned long sw, unsigned long sh, ImageDataColorSpace colorSpace), + Constructor(Float32Array data, unsigned long sw), + Constructor(Float32Array data, unsigned long sw, unsigned long sh), + Constructor(Float32Array data, unsigned long sw, unsigned long sh, ImageDataColorSpace colorSpace), + + Exposed=(Window,Worker), + RaisesException=Constructor, + RuntimeEnabled=ExperimentalCanvasFeatures, +] interface Float32ImageData { + readonly attribute unsigned long width; + readonly attribute unsigned long height; + readonly attribute Float32Array data; + readonly attribute ImageDataColorSpace colorSpace; +};
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index a07ec21..68d1351 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -793,7 +793,7 @@ return m_originClean; } -bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const { +bool HTMLCanvasElement::shouldAccelerate(AccelerationCriteria criteria) const { if (m_context && !m_context->is2d()) return false; @@ -809,8 +809,8 @@ if (layoutBox() && !layoutBox()->hasAcceleratedCompositing()) return false; - CheckedNumeric<int> checkedCanvasPixelCount = size.width(); - checkedCanvasPixelCount *= size.height(); + CheckedNumeric<int> checkedCanvasPixelCount = size().width(); + checkedCanvasPixelCount *= size().height(); if (!checkedCanvasPixelCount.IsValid()) return false; int canvasPixelCount = checkedCanvasPixelCount.ValueOrDie(); @@ -832,10 +832,12 @@ } // Do not use acceleration for small canvas. - Settings* settings = document().settings(); - if (!settings || - canvasPixelCount < settings->getMinimumAccelerated2dCanvasSize()) - return false; + if (criteria != IgnoreCanvasSizeAccelerationCriteria) { + Settings* settings = document().settings(); + if (!settings || + canvasPixelCount < settings->getMinimumAccelerated2dCanvasSize()) + return false; + } // When GPU allocated memory runs low (due to having created too many // accelerated canvases), the compositor starves and browser becomes laggy. @@ -873,7 +875,7 @@ } // namespace -bool HTMLCanvasElement::shouldUseDisplayList(const IntSize& deviceSize) { +bool HTMLCanvasElement::shouldUseDisplayList() { if (m_context->colorSpace() != kLegacyCanvasColorSpace) return false; @@ -887,15 +889,13 @@ } std::unique_ptr<ImageBufferSurface> -HTMLCanvasElement::createWebGLImageBufferSurface(const IntSize& deviceSize, - OpacityMode opacityMode) { +HTMLCanvasElement::createWebGLImageBufferSurface(OpacityMode opacityMode) { DCHECK(is3D()); // If 3d, but the use of the canvas will be for non-accelerated content // then make a non-accelerated ImageBuffer. This means copying the internal // Image will require a pixel readback, but that is unavoidable in this case. auto surface = WTF::wrapUnique(new AcceleratedImageBufferSurface( - deviceSize, opacityMode, m_context->skColorSpace(), - m_context->colorType())); + size(), opacityMode, m_context->skColorSpace(), m_context->colorType())); if (surface->isValid()) return std::move(surface); return nullptr; @@ -903,12 +903,8 @@ std::unique_ptr<ImageBufferSurface> HTMLCanvasElement::createAcceleratedImageBufferSurface( - const IntSize& deviceSize, OpacityMode opacityMode, int* msaaSampleCount) { - if (!shouldAccelerate(deviceSize)) - return nullptr; - if (document().settings()) { *msaaSampleCount = document().settings()->getAccelerated2dCanvasMSAASampleCount(); @@ -929,7 +925,7 @@ std::unique_ptr<ImageBufferSurface> surface = WTF::wrapUnique(new Canvas2DImageBufferSurface( - std::move(contextProvider), deviceSize, *msaaSampleCount, opacityMode, + std::move(contextProvider), size(), *msaaSampleCount, opacityMode, Canvas2DLayerBridge::EnableAcceleration, m_context->skColorSpace(), m_context->colorType())); if (!surface->isValid()) { @@ -945,12 +941,11 @@ std::unique_ptr<ImageBufferSurface> HTMLCanvasElement::createUnacceleratedImageBufferSurface( - const IntSize& deviceSize, OpacityMode opacityMode) { - if (shouldUseDisplayList(deviceSize)) { + if (shouldUseDisplayList()) { auto surface = WTF::wrapUnique(new RecordingImageBufferSurface( - deviceSize, WTF::wrapUnique(new UnacceleratedSurfaceFactory), - opacityMode, m_context->skColorSpace(), m_context->colorType())); + size(), WTF::wrapUnique(new UnacceleratedSurfaceFactory), opacityMode, + m_context->skColorSpace(), m_context->colorType())); if (surface->isValid()) { CanvasMetrics::countCanvasContextUsage( CanvasMetrics::DisplayList2DCanvasImageBufferCreated); @@ -961,9 +956,8 @@ } auto surfaceFactory = WTF::makeUnique<UnacceleratedSurfaceFactory>(); - auto surface = surfaceFactory->createSurface(deviceSize, opacityMode, - m_context->skColorSpace(), - m_context->colorType()); + auto surface = surfaceFactory->createSurface( + size(), opacityMode, m_context->skColorSpace(), m_context->colorType()); if (surface->isValid()) { CanvasMetrics::countCanvasContextUsage( CanvasMetrics::Unaccelerated2DCanvasImageBufferCreated); @@ -1000,12 +994,14 @@ if (externalSurface->isValid()) surface = std::move(externalSurface); } else if (is3D()) { - surface = createWebGLImageBufferSurface(size(), opacityMode); + surface = createWebGLImageBufferSurface(opacityMode); } else { - surface = createAcceleratedImageBufferSurface(size(), opacityMode, - &msaaSampleCount); + if (shouldAccelerate(NormalAccelerationCriteria)) { + surface = + createAcceleratedImageBufferSurface(opacityMode, &msaaSampleCount); + } if (!surface) { - surface = createUnacceleratedImageBufferSurface(size(), opacityMode); + surface = createUnacceleratedImageBufferSurface(opacityMode); } } if (!surface) @@ -1024,7 +1020,6 @@ return; } - m_imageBuffer->setClient(this); // Enabling MSAA overrides a request to disable antialiasing. This is true // regardless of whether the rendering mode is accelerated or not. For // consistency, we don't want to apply AA in accelerated canvases but not in @@ -1072,9 +1067,10 @@ // Four bytes per pixel per buffer. CheckedNumeric<intptr_t> checkedExternallyAllocatedMemory = 4 * bufferCount; - if (is3D()) + if (is3D()) { checkedExternallyAllocatedMemory += m_context->externallyAllocatedBytesPerPixel(); + } checkedExternallyAllocatedMemory *= width(); checkedExternallyAllocatedMemory *= height(); @@ -1214,6 +1210,21 @@ HTMLElement::didMoveToNewDocument(oldDocument); } +void HTMLCanvasElement::willDrawImageTo2DContext(CanvasImageSource* source) { + if (ExpensiveCanvasHeuristicParameters::EnableAccelerationToAvoidReadbacks && + source->isAccelerated() && !buffer()->isAccelerated() && + shouldAccelerate(IgnoreCanvasSizeAccelerationCriteria)) { + OpacityMode opacityMode = + m_context->creationAttributes().alpha() ? NonOpaque : Opaque; + int msaaSampleCount = 0; + std::unique_ptr<ImageBufferSurface> surface = + createAcceleratedImageBufferSurface(opacityMode, &msaaSampleCount); + if (surface) { + buffer()->setSurface(std::move(surface)); + } + } +} + PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas( SourceImageStatus* status, AccelerationHint hint, @@ -1261,8 +1272,9 @@ DisableAccelerationToAvoidReadbacks && !RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled() && hint == PreferNoAcceleration && m_context->isAccelerated() && - hasImageBuffer()) + hasImageBuffer()) { buffer()->disableAcceleration(); + } RefPtr<Image> image = renderingContext()->getImage(hint, reason); if (image) { skImage =
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index f1443be0..4025122 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -238,6 +238,8 @@ void detachContext() { m_context = nullptr; } + void willDrawImageTo2DContext(CanvasImageSource*); + protected: void didMoveToNewDocument(Document& oldDocument) override; @@ -250,7 +252,11 @@ static ContextFactoryVector& renderingContextFactories(); static CanvasRenderingContextFactory* getRenderingContextFactory(int); - bool shouldAccelerate(const IntSize&) const; + enum AccelerationCriteria { + NormalAccelerationCriteria, + IgnoreCanvasSizeAccelerationCriteria, + }; + bool shouldAccelerate(AccelerationCriteria) const; void parseAttribute(const AttributeModificationParams&) override; LayoutObject* createLayoutObject(const ComputedStyle&) override; @@ -259,19 +265,16 @@ void reset(); std::unique_ptr<ImageBufferSurface> createWebGLImageBufferSurface( - const IntSize& deviceSize, OpacityMode); std::unique_ptr<ImageBufferSurface> createAcceleratedImageBufferSurface( - const IntSize& deviceSize, OpacityMode, int* msaaSampleCount); std::unique_ptr<ImageBufferSurface> createUnacceleratedImageBufferSurface( - const IntSize& deviceSize, OpacityMode); void createImageBuffer(); void createImageBufferInternal( std::unique_ptr<ImageBufferSurface> externalSurface); - bool shouldUseDisplayList(const IntSize& deviceSize); + bool shouldUseDisplayList(); void setSurfaceSize(const IntSize&);
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp index 355814b..3cca1f6 100644 --- a/third_party/WebKit/Source/core/html/ImageData.cpp +++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -34,11 +34,163 @@ #include "core/frame/ImageBitmap.h" #include "core/imagebitmap/ImageBitmapOptions.h" #include "platform/RuntimeEnabledFeatures.h" -#include "wtf/CheckedNumeric.h" namespace blink { +bool ImageData::validateConstructorArguments(const unsigned& paramFlags, + const IntSize* size, + const unsigned& width, + const unsigned& height, + const DOMArrayBufferView* data, + const String* colorSpace, + ExceptionState* exceptionState, + ImageDataType imageDataType) { + if (paramFlags & kParamData) { + if (data->type() != DOMArrayBufferView::ViewType::TypeUint8Clamped && + data->type() != DOMArrayBufferView::ViewType::TypeFloat32) + return false; + if (data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped && + imageDataType != kUint8ClampedImageData) + imageDataType = kFloat32ImageData; + } + + // ImageData::create parameters without ExceptionState + if (paramFlags & kParamSize) { + if (!size->width() || !size->height()) + return false; + CheckedNumeric<unsigned> dataSize = 4; + dataSize *= size->width(); + dataSize *= size->height(); + if (!dataSize.IsValid()) + return false; + if (paramFlags & kParamData) { + DCHECK(data); + unsigned length = + data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped + ? (const_cast<DOMUint8ClampedArray*>( + static_cast<const DOMUint8ClampedArray*>(data))) + ->length() + : (const_cast<DOMFloat32Array*>( + static_cast<const DOMFloat32Array*>(data))) + ->length(); + if (dataSize.ValueOrDie() > length) + return false; + } + return true; + } + + // ImageData::create parameters with ExceptionState + if ((paramFlags & kParamWidth) && !width) { + exceptionState->throwDOMException( + IndexSizeError, "The source width is zero or not a number."); + return false; + } + if ((paramFlags & kParamHeight) && !height) { + exceptionState->throwDOMException( + IndexSizeError, "The source height is zero or not a number."); + return false; + } + if (paramFlags & (kParamWidth | kParamHeight)) { + CheckedNumeric<unsigned> dataSize = 4; + dataSize *= width; + dataSize *= height; + if (!dataSize.IsValid()) { + exceptionState->throwDOMException( + IndexSizeError, + "The requested image size exceeds the supported range."); + return false; + } + } + if (paramFlags & kParamData) { + DCHECK(data); + unsigned length = + data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped + ? (const_cast<DOMUint8ClampedArray*>( + static_cast<const DOMUint8ClampedArray*>(data))) + ->length() + : (const_cast<DOMFloat32Array*>( + static_cast<const DOMFloat32Array*>(data))) + ->length(); + if (!length) { + exceptionState->throwDOMException(IndexSizeError, + "The input data has zero elements."); + return false; + } + if (length % 4) { + exceptionState->throwDOMException( + IndexSizeError, "The input data length is not a multiple of 4."); + return false; + } + length /= 4; + if (length % width) { + exceptionState->throwDOMException( + IndexSizeError, + "The input data length is not a multiple of (4 * width)."); + return false; + } + if ((paramFlags & kParamHeight) && height != length / width) { + exceptionState->throwDOMException( + IndexSizeError, + "The input data length is not equal to (4 * width * height)."); + return false; + } + } + if (paramFlags & kParamColorSpace) { + if (!colorSpace || colorSpace->length() == 0) { + exceptionState->throwDOMException( + NotSupportedError, "The source color space is not defined."); + return false; + } + if (imageDataType == kUint8ClampedImageData && + *colorSpace != kLegacyImageDataColorSpaceName && + *colorSpace != kSRGBImageDataColorSpaceName) { + exceptionState->throwDOMException(NotSupportedError, + "The input color space is not " + "supported in " + "Uint8ClampedArray-backed ImageData."); + return false; + } + if (imageDataType == kFloat32ImageData && + *colorSpace != kLinearRGBImageDataColorSpaceName) { + exceptionState->throwDOMException(NotSupportedError, + "The input color space is not " + "supported in " + "Float32Array-backed ImageData."); + return false; + } + } + return true; +} + +DOMUint8ClampedArray* ImageData::allocateAndValidateUint8ClampedArray( + const unsigned& length, + ExceptionState* exceptionState) { + if (!length) + return nullptr; + DOMUint8ClampedArray* dataArray = DOMUint8ClampedArray::createOrNull(length); + if (!dataArray || length != dataArray->length()) { + if (exceptionState) { + exceptionState->throwDOMException(V8RangeError, + "Out of memory at ImageData creation"); + } + return nullptr; + } + return dataArray; +} + ImageData* ImageData::create(const IntSize& size) { + if (!ImageData::validateConstructorArguments(kParamSize, &size)) + return nullptr; + DOMUint8ClampedArray* byteArray = + ImageData::allocateAndValidateUint8ClampedArray(4 * size.width() * + size.height()); + if (!byteArray) + return nullptr; + return new ImageData(size, byteArray); +} + +// This function accepts size (0, 0). +ImageData* ImageData::createForTest(const IntSize& size) { CheckedNumeric<unsigned> dataSize = 4; dataSize *= size.width(); dataSize *= size.height(); @@ -55,94 +207,33 @@ ImageData* ImageData::create(const IntSize& size, DOMUint8ClampedArray* byteArray) { - CheckedNumeric<unsigned> dataSize = 4; - dataSize *= size.width(); - dataSize *= size.height(); - if (!dataSize.IsValid()) + if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size, + 0, 0, byteArray)) return nullptr; - - if (!dataSize.IsValid() || dataSize.ValueOrDie() > byteArray->length()) - return nullptr; - return new ImageData(size, byteArray); } ImageData* ImageData::create(unsigned width, unsigned height, ExceptionState& exceptionState) { - if (!width || !height) { - exceptionState.throwDOMException( - IndexSizeError, String::format("The source %s is zero or not a number.", - width ? "height" : "width")); + if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight, + nullptr, width, height, nullptr, + nullptr, &exceptionState)) return nullptr; - } - - CheckedNumeric<unsigned> dataSize = 4; - dataSize *= width; - dataSize *= height; - if (!dataSize.IsValid() || static_cast<int>(width) < 0 || - static_cast<int>(height) < 0) { - exceptionState.throwDOMException( - IndexSizeError, - "The requested image size exceeds the supported range."); - return nullptr; - } - DOMUint8ClampedArray* byteArray = - DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); - if (!byteArray) { - exceptionState.throwDOMException(V8Error, - "Out of memory at ImageData creation"); - return nullptr; - } - - return new ImageData(IntSize(width, height), byteArray); -} - -bool ImageData::validateConstructorArguments(DOMUint8ClampedArray* data, - unsigned width, - unsigned& lengthInPixels, - ExceptionState& exceptionState) { - if (!width) { - exceptionState.throwDOMException( - IndexSizeError, "The source width is zero or not a number."); - return false; - } - DCHECK(data); - unsigned length = data->length(); - if (!length) { - exceptionState.throwDOMException(IndexSizeError, - "The input data has a zero byte length."); - return false; - } - if (length % 4) { - exceptionState.throwDOMException( - IndexSizeError, "The input data byte length is not a multiple of 4."); - return false; - } - length /= 4; - if (length % width) { - exceptionState.throwDOMException( - IndexSizeError, - "The input data byte length is not a multiple of (4 * width)."); - return false; - } - lengthInPixels = length; - return true; + ImageData::allocateAndValidateUint8ClampedArray(4 * width * height, + &exceptionState); + return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr; } ImageData* ImageData::create(DOMUint8ClampedArray* data, unsigned width, ExceptionState& exceptionState) { - unsigned lengthInPixels = 0; - if (!validateConstructorArguments(data, width, lengthInPixels, - exceptionState)) { - DCHECK(exceptionState.hadException()); + if (!ImageData::validateConstructorArguments(kParamData | kParamWidth, + nullptr, width, 0, data, nullptr, + &exceptionState)) return nullptr; - } - DCHECK_GT(lengthInPixels, 0u); - DCHECK_GT(width, 0u); - unsigned height = lengthInPixels / width; + unsigned height = data->length() / (width * 4); return new ImageData(IntSize(width, height), data); } @@ -150,23 +241,81 @@ unsigned width, unsigned height, ExceptionState& exceptionState) { - unsigned lengthInPixels = 0; - if (!validateConstructorArguments(data, width, lengthInPixels, - exceptionState)) { - DCHECK(exceptionState.hadException()); + if (!ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamHeight, nullptr, width, height, data, + nullptr, &exceptionState)) return nullptr; - } - DCHECK_GT(lengthInPixels, 0u); - DCHECK_GT(width, 0u); - if (height != lengthInPixels / width) { - exceptionState.throwDOMException( - IndexSizeError, - "The input data byte length is not equal to (4 * width * height)."); - return nullptr; - } return new ImageData(IntSize(width, height), data); } +ImageDataColorSpace ImageData::getImageDataColorSpace(String colorSpaceName) { + if (colorSpaceName == kLegacyImageDataColorSpaceName) + return kLegacyImageDataColorSpace; + if (colorSpaceName == kSRGBImageDataColorSpaceName) + return kSRGBImageDataColorSpace; + if (colorSpaceName == kLinearRGBImageDataColorSpaceName) + return kLinearRGBImageDataColorSpace; + NOTREACHED(); + return kLegacyImageDataColorSpace; +} + +String ImageData::getImageDataColorSpaceName(ImageDataColorSpace colorSpace) { + switch (colorSpace) { + case kLegacyImageDataColorSpace: + return kLegacyImageDataColorSpaceName; + case kSRGBImageDataColorSpace: + return kSRGBImageDataColorSpaceName; + case kLinearRGBImageDataColorSpace: + return kLinearRGBImageDataColorSpaceName; + } + NOTREACHED(); + return String(); +} + +ImageData* ImageData::createImageData(unsigned width, + unsigned height, + String colorSpace, + ExceptionState& exceptionState) { + if (!ImageData::validateConstructorArguments( + kParamWidth | kParamHeight | kParamColorSpace, nullptr, width, height, + nullptr, &colorSpace, &exceptionState)) + return nullptr; + + DOMUint8ClampedArray* byteArray = + ImageData::allocateAndValidateUint8ClampedArray(4 * width * height, + &exceptionState); + return byteArray + ? new ImageData(IntSize(width, height), byteArray, colorSpace) + : nullptr; +} + +ImageData* ImageData::createImageData(DOMUint8ClampedArray* data, + unsigned width, + String colorSpace, + ExceptionState& exceptionState) { + if (!ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamColorSpace, nullptr, width, 0, data, + &colorSpace, &exceptionState)) + return nullptr; + unsigned height = data->length() / (width * 4); + return new ImageData(IntSize(width, height), data, colorSpace); +} + +ImageData* ImageData::createImageData(DOMUint8ClampedArray* data, + unsigned width, + unsigned height, + String colorSpace, + ExceptionState& exceptionState) { + if (!ImageData::validateConstructorArguments( + kParamData | kParamWidth | kParamHeight | kParamColorSpace, nullptr, + width, height, data, &colorSpace, &exceptionState)) + return nullptr; + return new ImageData(IntSize(width, height), data, colorSpace); +} + +// TODO(zakerinasab): Fix this when ImageBitmap color correction code is landed. +// Tip: If the source Image Data has a color space, createImageBitmap must +// respect this color space even when no color space tag is passed to it. ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, Optional<IntRect> cropRect, @@ -211,8 +360,12 @@ return wrapper; } -ImageData::ImageData(const IntSize& size, DOMUint8ClampedArray* byteArray) - : m_size(size), m_data(byteArray) { +ImageData::ImageData(const IntSize& size, + DOMUint8ClampedArray* byteArray, + String colorSpaceName) + : m_size(size), + m_colorSpace(getImageDataColorSpace(colorSpaceName)), + m_data(byteArray) { DCHECK_GE(size.width(), 0); DCHECK_GE(size.height(), 0); SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
diff --git a/third_party/WebKit/Source/core/html/ImageData.h b/third_party/WebKit/Source/core/html/ImageData.h index 206671a..286092d 100644 --- a/third_party/WebKit/Source/core/html/ImageData.h +++ b/third_party/WebKit/Source/core/html/ImageData.h
@@ -31,18 +31,44 @@ #include "bindings/core/v8/ScriptWrappable.h" #include "core/CoreExport.h" +#include "core/dom/DOMArrayBufferView.h" #include "core/dom/DOMTypedArray.h" #include "core/imagebitmap/ImageBitmapSource.h" #include "platform/geometry/IntRect.h" #include "platform/geometry/IntSize.h" #include "platform/heap/Handle.h" +#include "wtf/CheckedNumeric.h" #include "wtf/Compiler.h" +#include "wtf/text/WTFString.h" namespace blink { class ExceptionState; class ImageBitmapOptions; +enum ConstructorParams { + kParamSize = 1, + kParamWidth = 1 << 1, + kParamHeight = 1 << 2, + kParamData = 1 << 3, + kParamColorSpace = 1 << 4, +}; + +enum ImageDataType { + kUint8ClampedImageData, + kFloat32ImageData, +}; + +enum ImageDataColorSpace { + kLegacyImageDataColorSpace, + kSRGBImageDataColorSpace, + kLinearRGBImageDataColorSpace, +}; + +const char* const kLinearRGBImageDataColorSpaceName = "linear-rgb"; +const char* const kSRGBImageDataColorSpaceName = "srgb"; +const char* const kLegacyImageDataColorSpaceName = "legacy-srgb"; + class CORE_EXPORT ImageData final : public GarbageCollectedFinalized<ImageData>, public ScriptWrappable, public ImageBitmapSource { @@ -60,9 +86,30 @@ unsigned height, ExceptionState&); + static ImageData* createForTest(const IntSize&); + + ImageData* createImageData(unsigned width, + unsigned height, + String colorSpace, + ExceptionState&); + ImageData* createImageData(DOMUint8ClampedArray*, + unsigned width, + String colorSpace, + ExceptionState&); + ImageData* createImageData(DOMUint8ClampedArray*, + unsigned width, + unsigned height, + String colorSpace, + ExceptionState&); + + static ImageDataColorSpace getImageDataColorSpace(String); + static String getImageDataColorSpaceName(ImageDataColorSpace); + IntSize size() const { return m_size; } int width() const { return m_size.width(); } int height() const { return m_size.height(); } + String colorSpace() const { return getImageDataColorSpaceName(m_colorSpace); } + ImageDataColorSpace imageDataColorSpace() { return m_colorSpace; } const DOMUint8ClampedArray* data() const { return m_data.get(); } DOMUint8ClampedArray* data() { return m_data.get(); } @@ -81,16 +128,28 @@ const WrapperTypeInfo*, v8::Local<v8::Object> wrapper) override; - private: - ImageData(const IntSize&, DOMUint8ClampedArray*); + static bool validateConstructorArguments( + const unsigned&, + const IntSize* = nullptr, + const unsigned& = 0, + const unsigned& = 0, + const DOMArrayBufferView* = nullptr, + const String* = nullptr, + ExceptionState* = nullptr, + ImageDataType = kUint8ClampedImageData); - static bool validateConstructorArguments(DOMUint8ClampedArray*, - unsigned width, - unsigned&, - ExceptionState&); + private: + ImageData(const IntSize&, + DOMUint8ClampedArray*, + String = kLegacyImageDataColorSpaceName); IntSize m_size; + ImageDataColorSpace m_colorSpace; Member<DOMUint8ClampedArray> m_data; + + static DOMUint8ClampedArray* allocateAndValidateUint8ClampedArray( + const unsigned&, + ExceptionState* = nullptr); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/ImageData.idl b/third_party/WebKit/Source/core/html/ImageData.idl index d52d253..38051b0 100644 --- a/third_party/WebKit/Source/core/html/ImageData.idl +++ b/third_party/WebKit/Source/core/html/ImageData.idl
@@ -27,6 +27,9 @@ */ // https://html.spec.whatwg.org/#dom-imagedata +// https://github.com/junov/CanvasColorSpace/blob/master/CanvasColorSpaceProposal.md#imagedata + +enum ImageDataColorSpace { "legacy-srgb", "srgb", "linear-rgb" }; [ Constructor(unsigned long sw, unsigned long sh), @@ -34,8 +37,13 @@ Exposed=(Window,Worker), RaisesException=Constructor, ] interface ImageData { + + [RuntimeEnabled=ExperimentalCanvasFeatures, RaisesException] ImageData createImageData(unsigned long sw, unsigned long sh, ImageDataColorSpace colorSpace); + [RuntimeEnabled=ExperimentalCanvasFeatures, RaisesException] ImageData createImageData(Uint8ClampedArray data, unsigned long sw, ImageDataColorSpace colorSpace); + [RuntimeEnabled=ExperimentalCanvasFeatures, RaisesException] ImageData createImageData(Uint8ClampedArray data, unsigned long sw, unsigned long sh, ImageDataColorSpace colorSpace); + readonly attribute unsigned long width; readonly attribute unsigned long height; - // TODO(foolip): Expose data. - // readonly attribute Uint8ClampedArray data; + readonly attribute Uint8ClampedArray data; + readonly attribute ImageDataColorSpace colorSpace; };
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp index 6d1eff20..4050fa6 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -86,14 +86,11 @@ } void recordIdleTaskStatusHistogram( - CanvasAsyncBlobCreator::ToBlobFunctionType functionType, CanvasAsyncBlobCreator::IdleTaskStatus status) { - // TODO(crbug.com/653599): Add histograms for OffscreenCanvas.convertToBlob. - if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) - return; - DEFINE_STATIC_LOCAL(EnumerationHistogram, toBlobIdleTaskStatus, - ("Blink.Canvas.ToBlob.IdleTaskStatus", - CanvasAsyncBlobCreator::IdleTaskCount)); + DEFINE_THREAD_SAFE_STATIC_LOCAL( + EnumerationHistogram, toBlobIdleTaskStatus, + new EnumerationHistogram("Blink.Canvas.ToBlob.IdleTaskStatus", + CanvasAsyncBlobCreator::IdleTaskCount)); toBlobIdleTaskStatus.count(status); } @@ -107,52 +104,57 @@ }; void recordElapsedTimeHistogram( - CanvasAsyncBlobCreator::ToBlobFunctionType functionType, ElapsedTimeHistogramType type, CanvasAsyncBlobCreator::MimeType mimeType, double elapsedTime) { - // TODO(crbug.com/653599): Add histograms for OffscreenCanvas.convertToBlob. - if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) - return; - if (type == InitiateEncodingDelay) { if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobPNGInitiateEncodingCounter, - ("Blink.Canvas.ToBlob.InitiateEncodingDelay.PNG", 0, 10000000, 50)); + new CustomCountHistogram( + "Blink.Canvas.ToBlob.InitiateEncodingDelay.PNG", 0, 10000000, + 50)); toBlobPNGInitiateEncodingCounter.count(elapsedTime * 1000000.0); } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeJpeg) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobJPEGInitiateEncodingCounter, - ("Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", 0, 10000000, 50)); + new CustomCountHistogram( + "Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", 0, 10000000, + 50)); toBlobJPEGInitiateEncodingCounter.count(elapsedTime * 1000000.0); } } else if (type == IdleEncodeDuration) { if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobPNGIdleEncodeCounter, - ("Blink.Canvas.ToBlob.IdleEncodeDuration.PNG", 0, 10000000, 50)); + new CustomCountHistogram("Blink.Canvas.ToBlob.IdleEncodeDuration.PNG", + 0, 10000000, 50)); toBlobPNGIdleEncodeCounter.count(elapsedTime * 1000000.0); } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeJpeg) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobJPEGIdleEncodeCounter, - ("Blink.Canvas.ToBlob.IdleEncodeDuration.JPEG", 0, 10000000, 50)); + new CustomCountHistogram( + "Blink.Canvas.ToBlob.IdleEncodeDuration.JPEG", 0, 10000000, 50)); toBlobJPEGIdleEncodeCounter.count(elapsedTime * 1000000.0); } } else if (type == ToBlobDuration) { if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { - DEFINE_STATIC_LOCAL(CustomCountHistogram, toBlobPNGCounter, - ("Blink.Canvas.ToBlobDuration.PNG", 0, 10000000, 50)); + DEFINE_THREAD_SAFE_STATIC_LOCAL( + CustomCountHistogram, toBlobPNGCounter, + new CustomCountHistogram("Blink.Canvas.ToBlobDuration.PNG", 0, + 10000000, 50)); toBlobPNGCounter.count(elapsedTime * 1000000.0); } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeJpeg) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobJPEGCounter, - ("Blink.Canvas.ToBlobDuration.JPEG", 0, 10000000, 50)); + new CustomCountHistogram("Blink.Canvas.ToBlobDuration.JPEG", 0, + 10000000, 50)); toBlobJPEGCounter.count(elapsedTime * 1000000.0); } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeWebp) { - DEFINE_STATIC_LOCAL( + DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, toBlobWEBPCounter, - ("Blink.Canvas.ToBlobDuration.WEBP", 0, 10000000, 50)); + new CustomCountHistogram("Blink.Canvas.ToBlobDuration.WEBP", 0, + 10000000, 50)); toBlobWEBPCounter.count(elapsedTime * 1000000.0); } } @@ -296,7 +298,7 @@ void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality, double deadlineSeconds) { recordElapsedTimeHistogram( - m_functionType, InitiateEncodingDelay, MimeTypeJpeg, + InitiateEncodingDelay, MimeTypeJpeg, WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); if (m_idleTaskStatus == IdleTaskSwitchedToImmediateTask) { return; @@ -321,7 +323,7 @@ void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) { recordElapsedTimeHistogram( - m_functionType, InitiateEncodingDelay, MimeTypePng, + InitiateEncodingDelay, MimeTypePng, WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); if (m_idleTaskStatus == IdleTaskSwitchedToImmediateTask) { return; @@ -362,8 +364,7 @@ m_idleTaskStatus = IdleTaskCompleted; m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); - recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypePng, - m_elapsedTime); + recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypePng, m_elapsedTime); if (isDeadlineNearOrPassed(deadlineSeconds)) { TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask(BLINK_FROM_HERE, @@ -386,8 +387,7 @@ m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); if (m_numRowsCompleted == m_size.height()) { m_idleTaskStatus = IdleTaskCompleted; - recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypeJpeg, - m_elapsedTime); + recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypeJpeg, m_elapsedTime); if (isDeadlineNearOrPassed(deadlineSeconds)) { TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) @@ -458,8 +458,8 @@ } void CanvasAsyncBlobCreator::createBlobAndReturnResult() { - recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); - recordElapsedTimeHistogram(m_functionType, ToBlobDuration, m_mimeType, + recordIdleTaskStatusHistogram(m_idleTaskStatus); + recordElapsedTimeHistogram(ToBlobDuration, m_mimeType, WTF::monotonicallyIncreasingTime() - m_startTime); Blob* resultBlob = @@ -478,10 +478,10 @@ } void CanvasAsyncBlobCreator::createNullAndReturnResult() { - recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); + recordIdleTaskStatusHistogram(m_idleTaskStatus); if (m_functionType == HTMLCanvasToBlobCallback) { DCHECK(isMainThread()); - recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); + recordIdleTaskStatusHistogram(m_idleTaskStatus); TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent,
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp index 6a771c1..c5a39da 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
@@ -200,7 +200,7 @@ void CanvasAsyncBlobCreatorTest::prepareMockCanvasAsyncBlobCreatorFailPng() { IntSize testSize(0, 0); - ImageData* imageData = ImageData::create(testSize); + ImageData* imageData = ImageData::createForTest(testSize); // We reuse the class MockCanvasAsyncBlobCreatorWithoutCompletePng because // this test case is expected to fail at initialization step before @@ -229,7 +229,7 @@ void CanvasAsyncBlobCreatorTest::prepareMockCanvasAsyncBlobCreatorFailJpeg() { IntSize testSize(0, 0); - ImageData* imageData = ImageData::create(testSize); + ImageData* imageData = ImageData::createForTest(testSize); // We reuse the class MockCanvasAsyncBlobCreatorWithoutCompleteJpeg because // this test case is expected to fail at initialization step before
diff --git a/third_party/WebKit/Source/core/layout/BidiRun.h b/third_party/WebKit/Source/core/layout/BidiRun.h index b119dd7..e56869f1 100644 --- a/third_party/WebKit/Source/core/layout/BidiRun.h +++ b/third_party/WebKit/Source/core/layout/BidiRun.h
@@ -46,6 +46,17 @@ m_hasHyphen = false; } + BidiRun(int start, + int stop, + unsigned char level, + LineLayoutItem lineLayoutItem) + : BidiCharacterRun(start, stop, level), + m_lineLayoutItem(lineLayoutItem), + m_box(nullptr) { + // Stored in base class to save space. + m_hasHyphen = false; + } + BidiRun* next() { return static_cast<BidiRun*>(m_next); } public:
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index d90fd3f1..d45ad3a0 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -162,6 +162,7 @@ LayoutUnit position) const override; RootInlineBox* createAndAppendRootInlineBox(); + RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&); // Return the number of lines in *this* block flow. Does not recurse into // block flow children. @@ -872,7 +873,6 @@ InlineFlowBox* createLineBoxes(LineLayoutItem, const LineInfo&, InlineBox* childBox); - RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&); void setMarginsForRubyRun(BidiRun*, LayoutRubyRun*, LayoutObject*,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index ceda19d..3ad08c2 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -55,6 +55,7 @@ #include "core/layout/shapes/ShapeOutsideInfo.h" #include "core/page/AutoscrollController.h" #include "core/page/Page.h" +#include "core/page/scrolling/ScrollingCoordinator.h" #include "core/page/scrolling/SnapCoordinator.h" #include "core/paint/BackgroundImageGeometry.h" #include "core/paint/BoxPaintInvalidator.h" @@ -335,6 +336,11 @@ } } + if (diff.transformChanged()) { + if (ScrollingCoordinator* scrollingCoordinator = + document().frame()->page()->scrollingCoordinator()) + scrollingCoordinator->notifyTransformChanged(*this); + } // Non-atomic inlines should be LayoutInline or LayoutText, not LayoutBox. DCHECK(!isInline() || isAtomicInlineLevel()); }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc index 417b8d46..aa1fecfe 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
@@ -7,6 +7,7 @@ #include "core/layout/ng/ng_break_token.h" #include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_constraint_space_builder.h" +#include "core/layout/ng/ng_fragment.h" #include "core/layout/ng/ng_fragment_builder.h" #include "core/layout/ng/ng_inline_node.h" #include "core/layout/ng/ng_length_utils.h" @@ -69,6 +70,7 @@ case kStateFinalize: line_builder_->CreateFragments(builder_); *fragment_out = builder_->ToBoxFragment(); + line_builder_->CopyFragmentDataToLayoutBlockFlow(); state_ = kStateInit; return kNewFragment; };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc index d825058..5186ccd 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
@@ -4,12 +4,14 @@ #include "core/layout/ng/ng_inline_node.h" +#include "core/layout/LayoutBlockFlow.h" #include "core/layout/LayoutObject.h" #include "core/layout/LayoutText.h" #include "core/layout/ng/ng_bidi_paragraph.h" #include "core/layout/ng/ng_box_fragment.h" #include "core/layout/ng/ng_constraint_space_builder.h" #include "core/layout/ng/ng_fragment_builder.h" +#include "core/layout/ng/ng_line_builder.h" #include "core/layout/ng/ng_layout_inline_items_builder.h" #include "core/layout/ng/ng_physical_box_fragment.h" #include "core/layout/ng/ng_physical_text_fragment.h" @@ -80,7 +82,7 @@ while (node) { if (node->isText()) { builder->SetIsSVGText(node->isSVGInlineText()); - builder->Append(toLayoutText(node)->text(), node->style()); + builder->Append(toLayoutText(node)->text(), node->style(), node); } else if (node->isFloating() || node->isOutOfFlowPositioned()) { // Skip positioned objects. } else if (!node->isInline()) { @@ -91,7 +93,7 @@ // For atomic inlines add a unicode "object replacement character" to // signal the presence of a non-text object to the unicode bidi algorithm. if (node->isAtomicInlineLevel()) { - builder->Append(objectReplacementCharacter); + builder->Append(objectReplacementCharacter, nullptr, node); } // Otherwise traverse to children if they exist. @@ -239,8 +241,6 @@ return false; } - // TODO(layout-dev): Implement copying of fragment data to LayoutObject tree. - // Reset algorithm for future use layout_algorithm_ = nullptr; return true; @@ -257,6 +257,50 @@ return next_sibling_; } +// Find the first LayoutBlockFlow in the ancestor chain of |start_inilne_|. +LayoutBlockFlow* NGInlineNode::GetLayoutBlockFlow() const { + for (LayoutObject* layout_object = start_inline_->parent(); layout_object; + layout_object = layout_object->parent()) { + if (layout_object->isLayoutBlockFlow()) + return toLayoutBlockFlow(layout_object); + } + ASSERT_NOT_REACHED(); + return nullptr; +} + +// Compute the delta of text offsets between NGInlineNode and LayoutText. +// This map is needed to produce InlineTextBox since its offsets are to +// LayoutText. +// TODO(kojii): Since NGInlineNode has text after whitespace collapsed, the +// length may not match with LayoutText. This function updates LayoutText to +// match, but this needs more careful coding, if we keep copying to layoutobject +// tree. +void NGInlineNode::GetLayoutTextOffsets( + Vector<unsigned, 32>* text_offsets_out) { + LayoutText* current_text = nullptr; + unsigned current_offset = 0; + for (unsigned i = 0; i < items_.size(); i++) { + const NGLayoutInlineItem& item = items_[i]; + LayoutObject* next_object = item.GetLayoutObject(); + LayoutText* next_text = next_object && next_object->isText() + ? toLayoutText(next_object) + : nullptr; + if (next_text != current_text) { + if (current_text && + current_text->textLength() != item.StartOffset() - current_offset) { + current_text->setText(Text(current_offset, item.StartOffset()).impl()); + } + current_text = next_text; + current_offset = item.StartOffset(); + } + (*text_offsets_out)[i] = current_offset; + } + if (current_text && + current_text->textLength() != text_content_.length() - current_offset) { + current_text->setText(Text(current_offset, text_content_.length()).impl()); + } +} + DEFINE_TRACE(NGInlineNode) { visitor->trace(next_sibling_); visitor->trace(layout_algorithm_);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h index d0b6c0d..15f3040 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
@@ -18,6 +18,7 @@ namespace blink { class ComputedStyle; +class LayoutBlockFlow; class LayoutObject; class LayoutUnit; class NGConstraintSpace; @@ -49,6 +50,9 @@ Vector<NGLayoutInlineItem>& Items() { return items_; } NGLayoutInlineItemRange Items(unsigned start_index, unsigned end_index); + LayoutBlockFlow* GetLayoutBlockFlow() const; + void GetLayoutTextOffsets(Vector<unsigned, 32>*); + bool IsBidiEnabled() const { return is_bidi_enabled_; } DECLARE_VIRTUAL_TRACE(); @@ -86,14 +90,18 @@ // element where possible. class NGLayoutInlineItem { public: - NGLayoutInlineItem(unsigned start, unsigned end, const ComputedStyle* style) + NGLayoutInlineItem(unsigned start, + unsigned end, + const ComputedStyle* style, + LayoutObject* layout_object = nullptr) : start_offset_(start), end_offset_(end), bidi_level_(UBIDI_LTR), script_(USCRIPT_INVALID_CODE), fallback_priority_(FontFallbackPriority::Invalid), rotate_sideways_(false), - style_(style) { + style_(style), + layout_object_(layout_object) { DCHECK(end >= start); } @@ -105,6 +113,7 @@ UBiDiLevel BidiLevel() const { return bidi_level_; } UScriptCode Script() const { return script_; } const ComputedStyle* Style() const { return style_; } + LayoutObject* GetLayoutObject() const { return layout_object_; } void SetEndOffset(unsigned); @@ -127,6 +136,7 @@ bool rotate_sideways_; const ComputedStyle* style_; Vector<RefPtr<const ShapeResult>> shape_results_; + LayoutObject* layout_object_; friend class NGInlineNode; };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc index 1335f71d3..7f51d7b 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
@@ -30,7 +30,10 @@ void Append(const String& text, const ComputedStyle* style = nullptr) { unsigned start = text_content_.length(); text_content_.append(text); - items_.push_back(NGLayoutInlineItem(start, start + text.length(), style)); + // Pass non-null LayoutObject to indicate this is a text from LayoutText. + LayoutObject* layout_object = reinterpret_cast<LayoutObject*>(1); + items_.push_back( + NGLayoutInlineItem(start, start + text.length(), style, layout_object)); } void Append(UChar character) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc index 950a1775..57adefd0 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
@@ -96,10 +96,11 @@ } void NGLayoutInlineItemsBuilder::Append(const String& string, - const ComputedStyle* style) { + const ComputedStyle* style, + LayoutObject* layout_object) { if (string.isEmpty()) { unsigned offset = text_.length(); - items_->push_back(NGLayoutInlineItem(offset, offset, style)); + items_->push_back(NGLayoutInlineItem(offset, offset, style, layout_object)); return; } @@ -149,13 +150,22 @@ } } - items_->push_back(NGLayoutInlineItem(start_offset, text_.length(), style)); + items_->push_back( + NGLayoutInlineItem(start_offset, text_.length(), style, layout_object)); } -void NGLayoutInlineItemsBuilder::Append(UChar character) { +void NGLayoutInlineItemsBuilder::Append(UChar character, + const ComputedStyle* style, + LayoutObject* layout_object) { DCHECK(character != spaceCharacter && character != tabulationCharacter && character != newlineCharacter && character != zeroWidthSpaceCharacter); - AppendAsOpaqueToSpaceCollapsing(character); + if (has_pending_newline_) + ProcessPendingNewline(emptyString(), nullptr); + + text_.append(character); + unsigned end_offset = text_.length(); + items_->push_back( + NGLayoutInlineItem(end_offset - 1, end_offset, style, layout_object)); is_last_collapsible_space_ = false; }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h index 9d69786f..adeb6f9 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.h
@@ -46,13 +46,20 @@ // When appending, spaces are collapsed according to CSS Text, The white space // processing rules // https://drafts.csswg.org/css-text-3/#white-space-rules - void Append(const String&, const ComputedStyle*); + // @param style The style for the string. + // If a nullptr, it should skip shaping. Atomic inlines and bidi controls use + // this. + // @param LayoutObject The LayoutObject for the string. + // If a nullptr, it does not generate BidiRun. Bidi controls use this. + void Append(const String&, const ComputedStyle*, LayoutObject* = nullptr); // Append a character. // Currently this function is for adding control characters such as // objectReplacementCharacter, and does not support all space collapsing logic // as its String version does. - void Append(UChar); + // See the String version for using nullptr for ComputedStyle and + // LayoutObject. + void Append(UChar, const ComputedStyle* = nullptr, LayoutObject* = nullptr); // Append a character. // The character is opaque to space collapsing that spaces before this
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc index e1999af..7b85379 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
@@ -4,6 +4,10 @@ #include "core/layout/ng/ng_line_builder.h" +#include "core/layout/BidiRun.h" +#include "core/layout/LayoutBlockFlow.h" +#include "core/layout/line/LineInfo.h" +#include "core/layout/line/RootInlineBox.h" #include "core/layout/ng/ng_bidi_paragraph.h" #include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_fragment_builder.h" @@ -11,6 +15,7 @@ #include "core/layout/ng/ng_text_fragment.h" #include "core/layout/ng/ng_units.h" #include "core/style/ComputedStyle.h" +#include "platform/text/BidiRunList.h" namespace blink { @@ -43,10 +48,13 @@ const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); for (const auto& line_item_chunk : line_item_chunks_) { const NGLayoutInlineItem& start_item = items[line_item_chunk.start_index]; - const ComputedStyle* style = start_item.Style(); // Skip bidi controls. - if (!style) + if (!start_item.GetLayoutObject()) continue; + const ComputedStyle* style = start_item.Style(); + // TODO(kojii): Handling atomic inline needs more thoughts. + if (!style) + style = start_item.GetLayoutObject()->style(); // TODO(kojii): The block size for a text fragment isn't clear, revisit when // we implement line box layout. @@ -68,6 +76,11 @@ } DCHECK_EQ(fragments_.size(), offsets_.size()); + line_box_data_list_.grow(line_box_data_list_.size() + 1); + LineBoxData& line_box_data = line_box_data_list_.back(); + line_box_data.fragment_end = fragments_.size(); + line_box_data.inline_size = inline_offset; + max_inline_size_ = std::max(max_inline_size_, inline_offset); // TODO(kojii): Implement block size when we support baseline alignment. content_size_ += LayoutUnit(100); @@ -127,6 +140,81 @@ .SetBlockOverflow(content_size_); } +void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { + LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); + block->deleteLineBoxTree(); + + Vector<NGLayoutInlineItem>& items = inline_box_->Items(); + Vector<unsigned, 32> text_offsets(items.size()); + inline_box_->GetLayoutTextOffsets(&text_offsets); + + HeapVector<Member<const NGFragment>, 32> fragments_for_bidi_runs; + fragments_for_bidi_runs.reserveInitialCapacity(items.size()); + BidiRunList<BidiRun> bidi_runs; + LineInfo line_info; + unsigned fragment_index = 0; + for (const auto& line_box_data : line_box_data_list_) { + // Create a BidiRunList for this line. + for (; fragment_index < line_box_data.fragment_end; fragment_index++) { + const NGFragment* fragment = fragments_[fragment_index]; + const NGPhysicalTextFragment* text_fragment = + toNGPhysicalTextFragment(fragment->PhysicalFragment()); + // TODO(kojii): needs to reverse for RTL? + for (unsigned item_index = text_fragment->StartIndex(); + item_index < text_fragment->EndIndex(); item_index++) { + const NGLayoutInlineItem& item = items[item_index]; + LayoutObject* layout_object = item.GetLayoutObject(); + if (!layout_object) // Skip bidi controls. + continue; + BidiRun* run; + if (layout_object->isText()) { + unsigned text_offset = text_offsets[item_index]; + run = new BidiRun(item.StartOffset() - text_offset, + item.EndOffset() - text_offset, item.BidiLevel(), + LineLayoutItem(layout_object)); + } else { + DCHECK(layout_object->isAtomicInlineLevel()); + run = new BidiRun(0, 1, item.BidiLevel(), + LineLayoutItem(layout_object)); + } + bidi_runs.addRun(run); + fragments_for_bidi_runs.append(fragment); + } + } + // TODO(kojii): bidi needs to find the logical last run. + bidi_runs.setLogicallyLastRun(bidi_runs.lastRun()); + + // Create a RootInlineBox from BidiRunList. InlineBoxes created for the + // RootInlineBox are set to Bidirun::m_box. + line_info.setEmpty(false); + // TODO(kojii): Implement setFirstLine, LastLine, etc. + RootInlineBox* line_box = block->constructLine(bidi_runs, line_info); + + // Copy fragments data to InlineBoxes. + DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.runCount()); + BidiRun* run = bidi_runs.firstRun(); + for (const auto& fragment : fragments_for_bidi_runs) { + DCHECK(run); + InlineBox* inline_box = run->m_box; + inline_box->setLogicalWidth(fragment->InlineSize()); + inline_box->setLogicalLeft(fragment->InlineOffset()); + inline_box->setLogicalTop(fragment->BlockOffset()); + run = run->next(); + } + DCHECK(!run); + + // Copy LineBoxData to RootInlineBox. + line_box->setLogicalWidth(line_box_data.inline_size); + // TODO(kojii): Compute top/bottom/leading in |CreateLine()| and store in + // line_box_data. + line_box->setLineTopBottomPositions(LayoutUnit(), LayoutUnit(100), + LayoutUnit(), LayoutUnit(100)); + + bidi_runs.deleteRuns(); + fragments_for_bidi_runs.clear(); + } +} + DEFINE_TRACE(NGLineBuilder) { visitor->trace(inline_box_); visitor->trace(constraint_space_);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h index 2bb728b..702f220 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.h
@@ -32,6 +32,12 @@ // Create fragments for lines created by |CreateLine()|. void CreateFragments(NGFragmentBuilder*); + // Copy fragment data of all lines created by this NGLineBuilder to + // LayoutBlockFlow. + // This must run after |CreateFragments()|, and after the fragments it created + // are placed. + void CopyFragmentDataToLayoutBlockFlow(); + DECLARE_VIRTUAL_TRACE(); private: @@ -43,11 +49,22 @@ LayoutUnit inline_size; }; + // LineBoxData is a set of data for a line box that are computed in early + // phases, such as in |CreateLine()|, and will be used in later phases. + // TODO(kojii): Not sure if all these data are needed in fragment tree. If + // they are, we can create a linebox fragment, store them there, and this + // isn't needed. For now, we're trying to minimize data in fragments. + struct LineBoxData { + unsigned fragment_end; + LayoutUnit inline_size; + }; + Member<NGInlineNode> inline_box_; Member<const NGConstraintSpace> constraint_space_; HeapVector<Member<NGFragment>, 32> fragments_; Vector<NGLogicalOffset, 32> offsets_; Vector<LineItemChunk, 32> line_item_chunks_; + Vector<LineBoxData, 32> line_box_data_list_; LayoutUnit content_size_; LayoutUnit max_inline_size_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc index 198a1998..55509b48 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
@@ -57,7 +57,10 @@ for (; i < items.size(); i++) { const NGLayoutInlineItem& item = items[i]; // Split chunks before bidi controls, or at bidi level boundaries. - if (!item.Style() || item.BidiLevel() != start_item.BidiLevel()) { + // Also split at LayoutObject boundaries to generate InlineBox in + // |CopyFragmentDataToLayoutBlockFlow()|. + if (item.GetLayoutObject() != start_item.GetLayoutObject() || + !item.Style() || item.BidiLevel() != start_item.BidiLevel()) { break; } inline_size += item.InlineSize();
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePaintServer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePaintServer.cpp index ae34b3d..eae1e9ff 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePaintServer.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePaintServer.cpp
@@ -96,7 +96,7 @@ break; } - if (style.insideLink() == InsideVisitedLink) { + if (style.insideLink() == EInsideLink::kInsideVisitedLink) { // FIXME: This code doesn't support the uri component of the visited link // paint, https://bugs.webkit.org/show_bug.cgi?id=70006 SVGPaintType visitedPaintType = applyToFill
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index 27681120..15fd00d0 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -128,6 +128,18 @@ m_shouldScrollOnMainThreadDirty = true; } +void ScrollingCoordinator::notifyTransformChanged(const LayoutBox& box) { + if (m_page->deprecatedLocalMainFrame()->view()->needsLayout()) + return; + + for (PaintLayer* layer = box.enclosingLayer(); layer; + layer = layer->parent()) { + if (m_layersWithTouchRects.contains(layer)) { + m_touchEventTargetRectsAreDirty = true; + return; + } + } +} void ScrollingCoordinator::notifyOverflowUpdated() { m_scrollGestureRegionIsDirty = true; }
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h index 7d97eb4..9f681cd 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -41,6 +41,7 @@ class CompositorAnimationHost; class CompositorAnimationTimeline; +class LayoutBox; class LocalFrame; class FrameView; class GraphicsLayer; @@ -74,6 +75,8 @@ void notifyGeometryChanged(); // Called when any frame recalculates its overflows after style change. void notifyOverflowUpdated(); + // Called when any layoutBox has transform changed + void notifyTransformChanged(const LayoutBox&); void updateAfterCompositingChangeIfNeeded();
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index e4402ca..1b5ca74b 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -2162,7 +2162,7 @@ Color ComputedStyle::visitedDependentColor(int colorProperty) const { Color unvisitedColor = colorIncludingFallback(colorProperty, false); - if (insideLink() != InsideVisitedLink) + if (insideLink() != EInsideLink::kInsideVisitedLink) return unvisitedColor; Color visitedColor = colorIncludingFallback(colorProperty, true);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index 825e0e5..261bc9b 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -301,7 +301,8 @@ ComputedStyleBase::setBitDefaults(); m_inheritedData.m_hasSimpleUnderline = false; m_inheritedData.m_cursorStyle = static_cast<unsigned>(initialCursor()); - m_inheritedData.m_insideLink = NotInsideLink; + m_inheritedData.m_insideLink = + static_cast<unsigned>(EInsideLink::kNotInsideLink); m_nonInheritedData.m_effectiveDisplay = m_nonInheritedData.m_originalDisplay = @@ -2592,7 +2593,7 @@ return static_cast<EInsideLink>(m_inheritedData.m_insideLink); } void setInsideLink(EInsideLink insideLink) { - m_inheritedData.m_insideLink = insideLink; + m_inheritedData.m_insideLink = static_cast<unsigned>(insideLink); } bool hasExplicitlyInheritedProperties() const {
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h index 3df5a14..c9f8b42 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h +++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -405,7 +405,11 @@ None }; -enum EInsideLink { NotInsideLink, InsideUnvisitedLink, InsideVisitedLink }; +enum class EInsideLink : unsigned { + kNotInsideLink, + kInsideUnvisitedLink, + kInsideVisitedLink +}; enum ETransformStyle3D { TransformStyle3DFlat, TransformStyle3DPreserve3D };
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp index de42787..13a11e8 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -424,7 +424,8 @@ // FIXME: Is it a privacy violation to expose visited information to // accessibility APIs? return m_layoutObject->style()->isLink() && - m_layoutObject->style()->insideLink() == InsideVisitedLink; + m_layoutObject->style()->insideLink() == + EInsideLink::kInsideVisitedLink; } //
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp index 38d19c5..ff45c6d 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.cpp
@@ -124,7 +124,7 @@ // If the resolver is not in the set of ActiveAlgorithms then the frame // disconnected so we reject. - if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { + if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { resolver->reject( DOMException::create(NetworkError, kGATTServerDisconnected)); return; @@ -143,13 +143,14 @@ ScriptPromise BluetoothRemoteGATTCharacteristic::readValue( ScriptState* scriptState) { // We always check that the device is connected. - if (!gatt()->connected()) { + if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NetworkError, kGATTServerNotConnected)); } - if (!gatt()->device()->isValidCharacteristic(m_characteristic->instance_id)) { + if (!getGatt()->device()->isValidCharacteristic( + m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidStateError, kInvalidCharacteristic)); @@ -157,7 +158,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - gatt()->AddToActiveAlgorithms(resolver); + getGatt()->AddToActiveAlgorithms(resolver); mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); service->RemoteCharacteristicReadValue( @@ -179,7 +180,7 @@ // If the resolver is not in the set of ActiveAlgorithms then the frame // disconnected so we reject. - if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { + if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { resolver->reject( DOMException::create(NetworkError, kGATTServerDisconnected)); return; @@ -197,13 +198,14 @@ ScriptState* scriptState, const DOMArrayPiece& value) { // We always check that the device is connected. - if (!gatt()->connected()) { + if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NetworkError, kGATTServerNotConnected)); } - if (!gatt()->device()->isValidCharacteristic(m_characteristic->instance_id)) { + if (!getGatt()->device()->isValidCharacteristic( + m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidStateError, kInvalidCharacteristic)); @@ -226,7 +228,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - gatt()->AddToActiveAlgorithms(resolver); + getGatt()->AddToActiveAlgorithms(resolver); mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); service->RemoteCharacteristicWriteValue( @@ -247,7 +249,7 @@ // If the resolver is not in the set of ActiveAlgorithms then the frame // disconnected so we reject. - if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { + if (!getGatt()->RemoveFromActiveAlgorithms(resolver)) { resolver->reject( DOMException::create(NetworkError, kGATTServerDisconnected)); return; @@ -263,13 +265,14 @@ ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications( ScriptState* scriptState) { // We always check that the device is connected. - if (!gatt()->connected()) { + if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NetworkError, kGATTServerNotConnected)); } - if (!gatt()->device()->isValidCharacteristic(m_characteristic->instance_id)) { + if (!getGatt()->device()->isValidCharacteristic( + m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidStateError, kInvalidCharacteristic)); @@ -277,7 +280,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - gatt()->AddToActiveAlgorithms(resolver); + getGatt()->AddToActiveAlgorithms(resolver); mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); service->RemoteCharacteristicStartNotifications( @@ -292,13 +295,14 @@ ScriptPromise BluetoothRemoteGATTCharacteristic::stopNotifications( ScriptState* scriptState) { // We always check that the device is connected. - if (!gatt()->connected()) { + if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NetworkError, kGATTServerNotConnected)); } - if (!gatt()->device()->isValidCharacteristic(m_characteristic->instance_id)) { + if (!getGatt()->device()->isValidCharacteristic( + m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidStateError, kInvalidCharacteristic)); @@ -306,7 +310,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - gatt()->AddToActiveAlgorithms(resolver); + getGatt()->AddToActiveAlgorithms(resolver); mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); service->RemoteCharacteristicStopNotifications( @@ -357,13 +361,14 @@ ScriptState* scriptState, mojom::blink::WebBluetoothGATTQueryQuantity quantity, const String& descriptor) { - if (!gatt()->connected()) { + if (!getGatt()->connected()) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(NetworkError, kGATTServerNotConnected)); } - if (!gatt()->device()->isValidCharacteristic(m_characteristic->instance_id)) { + if (!getGatt()->device()->isValidCharacteristic( + m_characteristic->instance_id)) { return ScriptPromise::rejectWithDOMException( scriptState, DOMException::create(InvalidStateError, kInvalidCharacteristic)); @@ -371,7 +376,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - gatt()->AddToActiveAlgorithms(resolver); + getGatt()->AddToActiveAlgorithms(resolver); mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); WTF::Optional<String> uuid = WTF::nullopt;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h index 5731f0f9..c4aaabd 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.h
@@ -102,7 +102,7 @@ private: friend class BluetoothRemoteGATTDescriptor; - BluetoothRemoteGATTServer* gatt() { return m_service->device()->gatt(); } + BluetoothRemoteGATTServer* getGatt() { return m_service->device()->gatt(); } void ReadValueCallback(ScriptPromiseResolver*, mojom::blink::WebBluetoothResult,
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h index 59cab16..6a2fc29 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.h
@@ -53,7 +53,7 @@ private: friend class DescriptorReadValueCallback; - BluetoothRemoteGATTServer* getGatt() { return m_characteristic->gatt(); } + BluetoothRemoteGATTServer* getGatt() { return m_characteristic->getGatt(); } mojom::blink::WebBluetoothRemoteGATTDescriptorPtr m_descriptor; Member<BluetoothRemoteGATTCharacteristic> m_characteristic;
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp index b4be242..cda9d72b 100644 --- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
@@ -1174,6 +1174,10 @@ validateStateStack(); + willDrawImage(imageSource); + + validateStateStack(); + // Heuristic for disabling acceleration based on anticipated texture upload // overhead. // See comments in ExpensiveCanvasHeuristicParameters.h for explanation.
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h index 281f1d5..9ac6534d 100644 --- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h +++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
@@ -242,6 +242,8 @@ virtual ColorBehavior drawImageColorBehavior() const = 0; + virtual void willDrawImage(CanvasImageSource*) const {} + void restoreMatrixClipStack(SkCanvas*) const; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp index 37fc6a6..080321b 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -90,7 +90,7 @@ explicit CanvasRenderingContext2DAutoRestoreSkCanvas( CanvasRenderingContext2D* context) : m_context(context), m_saveCount(0) { - ASSERT(m_context); + DCHECK(m_context); SkCanvas* c = m_context->drawingCanvas(); if (c) { m_saveCount = c->getSaveCount(); @@ -195,7 +195,7 @@ return; // This code path is for restoring from an eviction // Restoring from surface failure is handled internally - ASSERT(m_contextLostMode != NotLostContext && !canvas()->hasImageBuffer()); + DCHECK(m_contextLostMode != NotLostContext && !canvas()->hasImageBuffer()); if (canvas()->buffer()) { if (contextLostRestoredEventsEnabled()) { @@ -268,6 +268,10 @@ } } +void CanvasRenderingContext2D::willDrawImage(CanvasImageSource* source) const { + canvas()->willDrawImageTo2DContext(source); +} + ColorBehavior CanvasRenderingContext2D::drawImageColorBehavior() const { return CanvasRenderingContext::colorBehaviorForMediaDrawnToCanvas(); } @@ -452,7 +456,7 @@ HashMap<String, Font>::iterator i = m_fontsResolvedUsingCurrentStyle.find(newFont); if (i != m_fontsResolvedUsingCurrentStyle.end()) { - ASSERT(m_fontLRUList.contains(newFont)); + DCHECK(m_fontLRUList.contains(newFont)); m_fontLRUList.remove(newFont); m_fontLRUList.add(newFont); modifiableState().setFont( @@ -474,7 +478,7 @@ canvas()->document().ensureStyleResolver().computeFont(fontStyle.get(), *parsedStyle); m_fontsResolvedUsingCurrentStyle.add(newFont, fontStyle->font()); - ASSERT(!m_fontLRUList.contains(newFont)); + DCHECK(!m_fontLRUList.contains(newFont)); m_fontLRUList.add(newFont); pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit schedulePruneLocalFontCacheIfNeeded(); // soft limit @@ -682,7 +686,7 @@ case CanvasRenderingContext2DState::DirectionLTR: return TextDirection::kLtr; } - ASSERT_NOT_REACHED(); + NOTREACHED(); return TextDirection::kLtr; } @@ -829,9 +833,10 @@ // anti-aliasing, which is expected when !creationAttributes().alpha(), so we // need to fall out of display list mode when drawing text to an opaque // canvas. crbug.com/583809 - if (!creationAttributes().alpha() && !isAccelerated()) + if (!creationAttributes().alpha() && !isAccelerated()) { canvas()->disableDeferral( DisableDeferralReasonSubPixelTextAntiAliasingSupport); + } const Font& font = accessFont(); font.getFontDescription().setSubpixelAscentDescent(true); @@ -1003,7 +1008,7 @@ bool CanvasRenderingContext2D::focusRingCallIsValid(const Path& path, Element* element) { - ASSERT(element); + DCHECK(element); if (!state().isTransformInvertible()) return false; if (path.isEmpty()) @@ -1090,9 +1095,10 @@ if (state().hasClip()) { hitRegionPath.intersectPath(state().getCurrentClipPath()); - if (hitRegionPath.isEmpty()) + if (hitRegionPath.isEmpty()) { exceptionState.throwDOMException(NotSupportedError, "The specified path has no pixels."); + } } if (!m_hitRegionManager)
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h index 2740912..ae240f1a 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
@@ -199,6 +199,8 @@ ColorBehavior drawImageColorBehavior() const final; + void willDrawImage(CanvasImageSource*) const final; + private: friend class CanvasRenderingContext2DAutoRestoreSkCanvas;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp index 43a45fe..59ebdfbb 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -1007,44 +1007,6 @@ savedFixedRenderingMode); } -TEST_F(CanvasRenderingContext2DTest, - PreferNoAccelerationHintDisablesAcceleration) { - bool savedFixedRenderingMode = - RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled(); - RuntimeEnabledFeatures::setCanvas2dFixedRenderingModeEnabled(false); - - createContext(NonOpaque); - FakeGLES2Interface gl; - std::unique_ptr<FakeWebGraphicsContext3DProvider> contextProvider( - new FakeWebGraphicsContext3DProvider(&gl)); - IntSize size(300, 300); - RefPtr<Canvas2DLayerBridge> bridge = - makeBridge(std::move(contextProvider), size, - Canvas2DLayerBridge::EnableAcceleration); - std::unique_ptr<Canvas2DImageBufferSurface> surface( - new Canvas2DImageBufferSurface(bridge, size)); - canvasElement().createImageBufferUsingSurfaceForTesting(std::move(surface)); - - EXPECT_TRUE(canvasElement().buffer()->isAccelerated()); - SourceImageStatus status = InvalidSourceImageStatus; - canvasElement().getSourceImageForCanvas( - &status, PreferNoAcceleration, SnapshotReasonUnitTests, FloatSize(size)); - EXPECT_EQ(NormalSourceImageStatus, status); - if (ExpensiveCanvasHeuristicParameters::DisableAccelerationToAvoidReadbacks) { - EXPECT_FALSE(canvasElement().buffer()->isAccelerated()); - EXPECT_EQ(0u, getGlobalAcceleratedImageBufferCount()); - EXPECT_EQ(0, getGlobalGPUMemoryUsage()); - } else { - EXPECT_TRUE(canvasElement().buffer()->isAccelerated()); - EXPECT_EQ(1u, getGlobalAcceleratedImageBufferCount()); - EXPECT_EQ(720000, getGlobalGPUMemoryUsage()); - } - - // Restore global state to prevent side-effects on other tests - RuntimeEnabledFeatures::setCanvas2dFixedRenderingModeEnabled( - savedFixedRenderingMode); -} - TEST_F(CanvasRenderingContext2DTest, TextureUploadHeuristics) { bool savedFixedRenderingMode = RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled();
diff --git a/third_party/WebKit/Source/modules/fetch/GlobalFetch.cpp b/third_party/WebKit/Source/modules/fetch/GlobalFetch.cpp index 25c7a74..f58d57c 100644 --- a/third_party/WebKit/Source/modules/fetch/GlobalFetch.cpp +++ b/third_party/WebKit/Source/modules/fetch/GlobalFetch.cpp
@@ -40,7 +40,8 @@ const RequestInfo& input, const Dictionary& init, ExceptionState& exceptionState) override { - if (!scriptState->contextIsValid()) { + ExecutionContext* executionContext = m_fetchManager->getExecutionContext(); + if (!scriptState->contextIsValid() || !executionContext) { // TODO(yhirano): Should this be moved to bindings? exceptionState.throwTypeError("The global scope is shutting down."); return ScriptPromise(); @@ -53,10 +54,8 @@ if (exceptionState.hadException()) return ScriptPromise(); - if (ExecutionContext* executionContext = - m_fetchManager->getExecutionContext()) - InspectorInstrumentation::willSendXMLHttpOrFetchNetworkRequest( - executionContext, r->url()); + InspectorInstrumentation::willSendXMLHttpOrFetchNetworkRequest( + executionContext, r->url()); return m_fetchManager->fetch(scriptState, r->passRequestData(scriptState)); }
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 3f892ec..85aa7103 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -219,7 +219,7 @@ ScrollTopLeftInterop status=experimental Sensor status=experimental ServiceWorkerNavigationPreload origin_trial_feature_name=ServiceWorkerNavigationPreload -SetRootScroller status=experimental +SetRootScroller status=experimental, origin_trial_feature_name=RootScroller ShadowPiercingDescendantCombinator status=experimental ShapeDetection status=experimental SharedArrayBuffer
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp index 5ad87f8..0efabea5 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -785,19 +785,24 @@ } void Canvas2DLayerBridge::flush() { - if (!getOrCreateSurface()) + if (!m_didDrawSinceLastFlush) return; TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush"); + if (!getOrCreateSurface()) + return; flushRecordingOnly(); getOrCreateSurface()->getCanvas()->flush(); + m_didDrawSinceLastFlush = false; } void Canvas2DLayerBridge::flushGpu() { - TRACE_EVENT0("cc", "Canvas2DLayerBridge::flushGpu"); flush(); gpu::gles2::GLES2Interface* gl = contextGL(); - if (isAccelerated() && gl) + if (isAccelerated() && gl && m_didDrawSinceLastGpuFlush) { + TRACE_EVENT0("cc", "Canvas2DLayerBridge::flushGpu"); gl->Flush(); + m_didDrawSinceLastGpuFlush = false; + } } gpu::gles2::GLES2Interface* Canvas2DLayerBridge::contextGL() { @@ -1053,6 +1058,8 @@ Platform::current()->currentThread()->addTaskObserver(this); m_isRegisteredTaskObserver = true; } + m_didDrawSinceLastFlush = true; + m_didDrawSinceLastGpuFlush = true; } void Canvas2DLayerBridge::prepareSurfaceForPaintingIfNeeded() {
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h index faf0123..0ba1285a 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -144,6 +144,8 @@ sk_sp<SkColorSpace> colorSpace() const { return m_colorSpace; } SkColorType colorType() const { return m_colorType; } + bool hasRecordedDrawCommands() { return m_haveRecordedDrawCommands; } + sk_sp<SkImage> newImageSnapshot(AccelerationHint, SnapshotReason); // The values of the enum entries must not change because they are used for @@ -266,6 +268,8 @@ bool m_surfaceCreationFailedAtLeastOnce = false; bool m_hibernationScheduled = false; bool m_dontUseIdleSchedulingForTesting = false; + bool m_didDrawSinceLastFlush = false; + bool m_didDrawSinceLastGpuFlush = false; friend class Canvas2DLayerBridgeTest; friend class CanvasRenderingContext2DTest;
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp index aeb1bfd..40a2e40a 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -1311,4 +1311,65 @@ EXPECT_EQ(1u, gl.destroyImageCount()); } +class FlushMockGLES2Interface : public gpu::gles2::GLES2InterfaceStub { + public: + MOCK_METHOD0(Flush, void()); +}; + +TEST_F(Canvas2DLayerBridgeTest, NoUnnecessaryFlushes) { + FlushMockGLES2Interface gl; + std::unique_ptr<FakeWebGraphicsContext3DProvider> contextProvider = + WTF::wrapUnique(new FakeWebGraphicsContext3DProvider(&gl)); + + EXPECT_CALL(gl, Flush()).Times(0); + Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge( + std::move(contextProvider), IntSize(300, 150), 0, NonOpaque, + Canvas2DLayerBridge::ForceAccelerationForTesting, nullptr, + kN32_SkColorType))); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(0); + bridge->didDraw(FloatRect(0, 0, 1, 1)); + EXPECT_TRUE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(1); + bridge->flushGpu(); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(0); + bridge->didDraw(FloatRect(0, 0, 1, 1)); + EXPECT_TRUE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(1); + bridge->flushGpu(); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + // No flush because already flushed since last draw + EXPECT_CALL(gl, Flush()).Times(0); + bridge->flushGpu(); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(0); + bridge->didDraw(FloatRect(0, 0, 1, 1)); + EXPECT_TRUE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + // Flushes recording, but not the gpu + EXPECT_CALL(gl, Flush()).Times(0); + bridge->flush(); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); + + EXPECT_CALL(gl, Flush()).Times(1); + bridge->flushGpu(); + EXPECT_FALSE(bridge->hasRecordedDrawCommands()); + ::testing::Mock::VerifyAndClearExpectations(&gl); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h index b9c71588..3fbcba25 100644 --- a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h +++ b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
@@ -60,20 +60,11 @@ // lists. Rationale: The allocation of large textures for canvas // tends to starve the compositor, and increase the probability of // failure of subsequent allocations required for double buffering. - PreferDisplayListOverGpuSizeThreshold = 4096 * 4096, + PreferDisplayListOverGpuSizeThreshold = 8096 * 4096, // Disable Acceleration heuristic parameters //=========================================== - GetImageDataForcesNoAcceleration = 1, - - // When a canvas is used as a source image, if its destination is - // non-accelerated and the source canvas is accelerated, a readback - // from the gpu is necessary. This option causes the source canvas to - // switch to non-accelerated when this situation is encountered to - // prevent future canvas-to-canvas draws from requiring a readback. - DisableAccelerationToAvoidReadbacks = 1, - // When drawing very large images to canvases, there is a point where // GPU acceleration becomes inefficient due to texture upload overhead, // especially when the image is large enough that it is likely to @@ -84,6 +75,27 @@ DrawImageTextureUploadSoftSizeLimitScaleThreshold = 4, DrawImageTextureUploadHardSizeLimit = 8192 * 8192, + // GPU readback prevention heuristics + //==================================== + + GetImageDataForcesNoAcceleration = 1, + + // When a canvas is used as a source image, if its destination is + // non-accelerated and the source canvas is accelerated, a readback + // from the gpu is necessary. This option causes the source canvas to + // switch to non-accelerated when this situation is encountered to + // prevent future canvas-to-canvas draws from requiring a readback. + DisableAccelerationToAvoidReadbacks = 0, + + // See description of DisableAccelerationToAvoidReadbacks. This is the + // opposite strategy : accelerate the destination canvas. If both + // EnableAccelerationToAvoidReadbacks and + // DisableAccelerationToAvoidReadbacks are specified, we try to enable + // acceleration on the destination first. If that does not succeed, + // we disable acceleration on the source canvas. Either way, future + // readbacks are prevented. + EnableAccelerationToAvoidReadbacks = 1, + }; // enum // Constants and Coefficients for 2D Canvas Dynamic Rendering Mode Switching
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index 4982dd7..493a379 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -146,16 +146,6 @@ return m_client ? m_client->isDirty() : false; } -void ImageBuffer::didDisableAcceleration() const { - DCHECK(m_gpuMemoryUsage); - DCHECK_GT(s_globalAcceleratedImageBufferCount, 0u); - if (m_client) - m_client->didDisableAcceleration(); - s_globalAcceleratedImageBufferCount--; - s_globalGPUMemoryUsage -= m_gpuMemoryUsage; - m_gpuMemoryUsage = 0; -} - void ImageBuffer::didFinalizeFrame() { if (m_client) m_client->didFinalizeFrame(); @@ -367,8 +357,9 @@ DCHECK(canvas()); if (ExpensiveCanvasHeuristicParameters::GetImageDataForcesNoAcceleration && - !RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled()) + !RuntimeEnabledFeatures::canvas2dFixedRenderingModeEnabled()) { const_cast<ImageBuffer*>(this)->disableAcceleration(); + } sk_sp<SkImage> snapshot = m_surface->newImageSnapshot( PreferNoAcceleration, SnapshotReasonGetImageData); @@ -442,22 +433,22 @@ if (!isSurfaceValid()) return; - ASSERT(sourceRect.width() > 0); - ASSERT(sourceRect.height() > 0); + DCHECK_GT(sourceRect.width(), 0); + DCHECK_GT(sourceRect.height(), 0); int originX = sourceRect.x(); int destX = destPoint.x() + sourceRect.x(); - ASSERT(destX >= 0); - ASSERT(destX < m_surface->size().width()); - ASSERT(originX >= 0); - ASSERT(originX < sourceRect.maxX()); + DCHECK_GE(destX, 0); + DCHECK_LT(destX, m_surface->size().width()); + DCHECK_GE(originX, 0); + DCHECK_LT(originX, sourceRect.maxX()); int originY = sourceRect.y(); int destY = destPoint.y() + sourceRect.y(); - ASSERT(destY >= 0); - ASSERT(destY < m_surface->size().height()); - ASSERT(originY >= 0); - ASSERT(originY < sourceRect.maxY()); + DCHECK_GE(destY, 0); + DCHECK_LT(destY, m_surface->size().height()); + DCHECK_GE(originY, 0); + DCHECK_LT(originY, sourceRect.maxY()); const size_t srcBytesPerRow = 4 * sourceSize.width(); const void* srcAddr = source + originY * srcBytesPerRow + originX * 4; @@ -492,6 +483,9 @@ s_globalAcceleratedImageBufferCount--; s_globalGPUMemoryUsage -= m_gpuMemoryUsage; m_gpuMemoryUsage = 0; + + if (m_client) + m_client->didDisableAcceleration(); } } @@ -519,12 +513,6 @@ if (!isAccelerated()) return; - sk_sp<SkImage> image = - m_surface->newImageSnapshot(PreferNoAcceleration, SnapshotReasonPaint); - // Using a GPU-backed image with RecordingImageBufferSurface - // will fail at playback time. - image = image->makeNonTextureImage(); - // Create and configure a recording (unaccelerated) surface. std::unique_ptr<RecordingImageBufferFallbackSurfaceFactory> surfaceFactory = WTF::makeUnique<UnacceleratedSurfaceFactory>(); @@ -532,13 +520,26 @@ WTF::wrapUnique(new RecordingImageBufferSurface( m_surface->size(), std::move(surfaceFactory), m_surface->getOpacityMode(), m_surface->colorSpace())); + setSurface(std::move(surface)); +} + +void ImageBuffer::setSurface(std::unique_ptr<ImageBufferSurface> surface) { + sk_sp<SkImage> image = + m_surface->newImageSnapshot(PreferNoAcceleration, SnapshotReasonPaint); + + if (surface->isRecording()) { + // Using a GPU-backed image with RecordingImageBufferSurface + // will fail at playback time. + image = image->makeNonTextureImage(); + } + surface->canvas()->drawImage(image.get(), 0, 0); surface->setImageBuffer(this); if (m_client) m_client->restoreCanvasMatrixClipStack(surface->canvas()); m_surface = std::move(surface); - didDisableAcceleration(); + updateGPUMemoryUsage(); } bool ImageDataBuffer::encodeImage(const String& mimeType, @@ -556,7 +557,7 @@ } else { if (!PNGImageEncoder::encode(*this, encodedImage)) return false; - ASSERT(mimeType == "image/png"); + DCHECK_EQ(mimeType, "image/png"); } return true; @@ -564,7 +565,7 @@ String ImageDataBuffer::toDataURL(const String& mimeType, const double& quality) const { - ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + DCHECK(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); Vector<unsigned char> result; if (!encodeImage(mimeType, quality, &result))
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h index 435e534..4fed4e1 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -101,7 +101,6 @@ bool wasDrawnToAfterSnapshot() const { return m_snapshotState == DrawnToAfterSnapshot; } - void didDisableAcceleration() const; void setFilterQuality(SkFilterQuality filterQuality) { m_surface->setFilterQuality(filterQuality); @@ -182,6 +181,7 @@ intptr_t getGPUMemoryUsage() { return m_gpuMemoryUsage; } void disableAcceleration(); + void setSurface(std::unique_ptr<ImageBufferSurface>); WeakPtrFactory<ImageBuffer> m_weakPtrFactory;
diff --git a/third_party/WebKit/Source/platform/text/BidiCharacterRun.h b/third_party/WebKit/Source/platform/text/BidiCharacterRun.h index 95306b4..f8f839c 100644 --- a/third_party/WebKit/Source/platform/text/BidiCharacterRun.h +++ b/third_party/WebKit/Source/platform/text/BidiCharacterRun.h
@@ -60,6 +60,13 @@ } } + BidiCharacterRun(int start, int stop, unsigned char level) + : m_override(false), + m_level(level), + m_next(0), + m_start(start), + m_stop(stop) {} + // BidiCharacterRun are allocated out of the rendering partition. PLATFORM_EXPORT void* operator new(size_t); PLATFORM_EXPORT void operator delete(void*);
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.cpp b/third_party/WebKit/Source/wtf/text/WTFString.cpp index 3b04de8..0cfe473 100644 --- a/third_party/WebKit/Source/wtf/text/WTFString.cpp +++ b/third_party/WebKit/Source/wtf/text/WTFString.cpp
@@ -42,6 +42,31 @@ using namespace Unicode; +namespace { + +Vector<char> asciiDebug(StringImpl* impl) { + if (!impl) + return asciiDebug(String("[null]").impl()); + + Vector<char> buffer; + for (unsigned i = 0; i < impl->length(); ++i) { + UChar ch = (*impl)[i]; + if (isASCIIPrintable(ch)) { + if (ch == '\\') + buffer.push_back('\\'); + buffer.push_back(static_cast<char>(ch)); + } else { + buffer.push_back('\\'); + buffer.push_back('u'); + appendUnsignedAsHexFixedSize(ch, buffer, 4); + } + } + buffer.push_back('\0'); + return buffer; +} + +} // namespace + // Construct a string with UTF-16 data. String::String(const UChar* characters, unsigned length) : m_impl(characters ? StringImpl::create(characters, length) : nullptr) {} @@ -811,46 +836,10 @@ return out << '"'; } -} // namespace WTF - #ifndef NDEBUG -// For use in the debugger -String* string(const char*); -Vector<char> asciiDebug(StringImpl*); -Vector<char> asciiDebug(String&); - void String::show() const { dataLogF("%s\n", asciiDebug(impl()).data()); } - -String* string(const char* s) { - // leaks memory! - return new String(s); -} - -Vector<char> asciiDebug(StringImpl* impl) { - if (!impl) - return asciiDebug(String("[null]").impl()); - - Vector<char> buffer; - for (unsigned i = 0; i < impl->length(); ++i) { - UChar ch = (*impl)[i]; - if (isASCIIPrintable(ch)) { - if (ch == '\\') - buffer.push_back('\\'); - buffer.push_back(static_cast<char>(ch)); - } else { - buffer.push_back('\\'); - buffer.push_back('u'); - appendUnsignedAsHexFixedSize(ch, buffer, 4); - } - } - buffer.push_back('\0'); - return buffer; -} - -Vector<char> asciiDebug(String& string) { - return asciiDebug(string.impl()); -} - #endif + +} // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.h b/third_party/WebKit/Source/wtf/text/WTFString.h index db63892..6fe8763 100644 --- a/third_party/WebKit/Source/wtf/text/WTFString.h +++ b/third_party/WebKit/Source/wtf/text/WTFString.h
@@ -426,6 +426,7 @@ } #ifndef NDEBUG + // For use in the debugger. void show() const; #endif
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 09d8d60..a041526 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -264,11 +264,12 @@ optparse.make_option( "--child-processes", help="Number of drivers to run in parallel."), + # TODO(tkent): Remove --enable-wptserve. optparse.make_option( "--enable-wptserve", dest="enable_wptserve", action="store_true", - default=False, + default=True, help="Enable running web-platform-tests using WPTserve instead of Apache."), optparse.make_option( "--disable-breakpad",
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 5ff826f91..7d4422f1 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -4210,6 +4210,11 @@ in canvas.toBlob. When the encoding idle task is delayed for longer than IdleTaskCompleteTimeoutDelay, the browser will switch to a non-idle task to force encoding to happen on the main thread. + + In addition, metric values from OffscreenCanvas.convertToBlob API call are + also gathered into this histogram, because the logic flow is exactly the + same as canvas.toBlob. It's worth to note that the values can come from idle + tasks on either main or worker thread. </summary> </histogram> @@ -4218,6 +4223,11 @@ <owner>xlai@chromium.org</owner> <summary> Records the status of the idle task when finishing a toBlob call. + + In addition, metric values from OffscreenCanvas.convertToBlob API call are + also gathered into this histogram, because the logic flow is exactly the + same as canvas.toBlob. It's worth to note that the values can come from idle + tasks on either main or worker thread. </summary> </histogram> @@ -4234,13 +4244,25 @@ canvas.toBlob. When the initialization idle task is delayed for longer than IdleTaskStartTimeoutDelay, the browser will switch to a non-idle task to force initialization and encoding to occur on the main thread. + + In addition, metric values from OffscreenCanvas.convertToBlob API call are + also gathered into this histogram, because the logic flow is exactly the + same as canvas.toBlob. It's worth to note that the values can come from idle + tasks on either main or worker thread. </summary> </histogram> <histogram name="Blink.Canvas.ToBlobDuration" units="microseconds"> <owner>junov@chromium.org</owner> <owner>xlai@chromium.org</owner> - <summary>Time spent on 2D canvas toBlob API call.</summary> + <summary> + Time spent on 2D canvas toBlob API call. + + In addition, metric values from OffscreenCanvas.convertToBlob API call are + also gathered into this histogram, because the logic flow is exactly the + same as canvas.toBlob. It's worth to note that the values can come from idle + tasks on either main or worker thread. + </summary> </histogram> <histogram name="Blink.Canvas.ToDataURL" units="microseconds"> @@ -24151,6 +24173,14 @@ <summary>Records the autoplay source of audios.</summary> </histogram> +<histogram name="Media.Audio.Capture.CallbackError" enum="BooleanError"> + <owner>tommi@chromium.org</owner> + <summary> + A boolean that reflects whether or not an error was reported during audio + capture. + </summary> +</histogram> + <histogram name="Media.Audio.Capture.FramesProvided" units="frames"> <owner>grunell@chromium.org</owner> <summary> @@ -48749,6 +48779,22 @@ </summary> </histogram> +<histogram name="Power.ConnectedChargingPorts" + enum="PowerConnectedChargingPorts"> + <owner>bleung@chromium.org</owner> + <owner>derat@chromium.org</owner> + <summary> + Connected charging ports on Chrome OS. A sample is reported every time that + the power manager polls sysfs (typically every 30 seconds). Ordinals are + assigned based on the lexicographical ordering of power supply names from + sysfs and have no implied correspondence with ports' physical locations. For + example, with ports 'CROS_USB_PD_CHARGER0' and 'CROS_USB_PD_CHARGER1', + 'first' refers to the former and 'second' to the latter. To determine a + port's physical location, see the powerd charging_ports pref in the device's + overlay. + </summary> +</histogram> + <histogram name="Power.DarkResumeWakeDurationMs" units="ms"> <owner>chirantan@chromium.org</owner> <summary> @@ -84166,6 +84212,9 @@ <int value="55" label="AD policy fetch fail"> Active Directory policy fetch failed. </int> + <int value="56" label="Store DM token failed"> + Failed to store DM token into the local state. + </int> </enum> <enum name="EnterprisePolicies" type="int"> @@ -100453,6 +100502,17 @@ <int value="4" label="Safe Spring Charger"/> </enum> +<enum name="PowerConnectedChargingPorts" type="int"> + <summary> + Connected charging ports on Chrome OS, as reported by the kernel. + </summary> + <int value="0" label="No ports connected"/> + <int value="1" label="First port connected"/> + <int value="2" label="Second port connected"/> + <int value="3" label="First and second ports connected"/> + <int value="4" label="More than two ports exist"/> +</enum> + <enum name="PowerSupplyType" type="int"> <summary> The type of power supply connected to a Chrome OS system, as reported by the @@ -109834,6 +109894,8 @@ <suffix name="toDataURL" label="Image formats passed to canvas.toDataURL"/> <suffix name="toBlobCallback" label="Image formats passed to canvas.toBlob (callback)"/> + <suffix name="convertToBlobPromise" + label="Image formats passed to OffscreenCanvas.convertToBlob (promise)"/> <affected-histogram name="Canvas.RequestedImageMimeTypes"/> </histogram_suffixes>
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index 2331252..b9d1a27 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -198,8 +198,7 @@ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY -@decorators.Disabled('win', # crbug.com/662971 - 'mac') # crbug.com/663025 +@decorators.Disabled('win') # crbug.com/662971 class TwitterDesktopStory(_NewsBrowsingStory): NAME = 'browse:social:twitter' URL = 'https://www.twitter.com/nasa'
diff --git a/ui/aura/mus/input_method_mus.cc b/ui/aura/mus/input_method_mus.cc index fdce898..230dfff 100644 --- a/ui/aura/mus/input_method_mus.cc +++ b/ui/aura/mus/input_method_mus.cc
@@ -92,9 +92,8 @@ UpdateTextInputType(); InputMethodBase::OnTextInputTypeChanged(client); - if (input_method_) { + if (input_method_) input_method_->OnTextInputTypeChanged(client->GetTextInputType()); - } } void InputMethodMus::OnCaretBoundsChanged(const ui::TextInputClient* client) { @@ -124,10 +123,22 @@ InputMethodBase::OnDidChangeFocusedClient(focused_before, focused); UpdateTextInputType(); + // TODO(moshayedi): crbug.com/681563. Handle when there is no focused clients. + if (!focused) + return; + text_input_client_ = base::MakeUnique<TextInputClientImpl>(focused); if (ime_server_) { - ime_server_->StartSession(text_input_client_->CreateInterfacePtrAndBind(), - MakeRequest(&input_method_)); + ui::mojom::StartSessionDetailsPtr details = + ui::mojom::StartSessionDetails::New(); + details->client = text_input_client_->CreateInterfacePtrAndBind(); + details->input_method_request = MakeRequest(&input_method_); + details->text_input_type = focused->GetTextInputType(); + details->text_input_mode = focused->GetTextInputMode(); + details->text_direction = focused->GetTextDirection(); + details->text_input_flags = focused->GetTextInputFlags(); + details->caret_bounds = focused->GetCaretBounds(); + ime_server_->StartSession(std::move(details)); } }
diff --git a/ui/aura/window.cc b/ui/aura/window.cc index db48036..83a532b 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc
@@ -1096,7 +1096,7 @@ } std::unique_ptr<ui::EventTargetIterator> Window::GetChildIterator() const { - return base::MakeUnique<ui::EventTargetIteratorImpl<Window>>(children()); + return base::MakeUnique<ui::EventTargetIteratorPtrImpl<Window>>(children()); } ui::EventTargeter* Window::GetEventTargeter() {
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index 02495f46..4ccccb4 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc
@@ -158,10 +158,10 @@ void WindowEventDispatcher::ProcessedTouchEvent(uint32_t unique_event_id, Window* window, ui::EventResult result) { - std::unique_ptr<ui::GestureRecognizer::Gestures> gestures( + ui::GestureRecognizer::Gestures gestures = ui::GestureRecognizer::Get()->AckTouchEvent(unique_event_id, result, - window)); - DispatchDetails details = ProcessGestures(window, gestures.get()); + window); + DispatchDetails details = ProcessGestures(window, std::move(gestures)); if (details.dispatcher_destroyed) return; } @@ -275,9 +275,9 @@ ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures( Window* target, - ui::GestureRecognizer::Gestures* gestures) { + ui::GestureRecognizer::Gestures gestures) { DispatchDetails details; - if (!gestures || gestures->empty()) + if (gestures.empty()) return details; // If a window has been hidden between the touch event and now, the associated @@ -285,10 +285,9 @@ if (!target) return details; - for (size_t i = 0; i < gestures->size(); ++i) { - ui::GestureEvent* event = gestures->get().at(i); + for (const auto& event : gestures) { event->ConvertLocationToTarget(window(), target); - details = DispatchEvent(target, event); + details = DispatchEvent(target, event.get()); if (details.dispatcher_destroyed || details.target_destroyed) break; } @@ -486,13 +485,12 @@ const ui::TouchEvent& touchevent = *event.AsTouchEvent(); if (!touchevent.synchronous_handling_disabled()) { - std::unique_ptr<ui::GestureRecognizer::Gestures> gestures; - Window* window = static_cast<Window*>(target); - gestures.reset(ui::GestureRecognizer::Get()->AckTouchEvent( - touchevent.unique_event_id(), event.result(), window)); + ui::GestureRecognizer::Gestures gestures = + ui::GestureRecognizer::Get()->AckTouchEvent( + touchevent.unique_event_id(), event.result(), window); - return ProcessGestures(window, gestures.get()); + return ProcessGestures(window, std::move(gestures)); } } }
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h index b4cfb13..219037c 100644 --- a/ui/aura/window_event_dispatcher.h +++ b/ui/aura/window_event_dispatcher.h
@@ -154,7 +154,7 @@ WARN_UNUSED_RESULT; ui::EventDispatchDetails ProcessGestures( Window* target, - ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT; + ui::GestureRecognizer::Gestures gestures) WARN_UNUSED_RESULT; // Called when a window becomes invisible, either by being removed // from root window hierarchy, via SetVisible(false) or being destroyed.
diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc index 584c1a10..1adb0004 100644 --- a/ui/chromeos/touch_exploration_controller.cc +++ b/ui/chromeos/touch_exploration_controller.cc
@@ -846,24 +846,20 @@ ui::GestureEvent* gesture) {} void TouchExplorationController::ProcessGestureEvents() { - std::unique_ptr<ScopedVector<ui::GestureEvent>> gestures( - gesture_provider_->GetAndResetPendingGestures()); - if (gestures) { - for (ScopedVector<GestureEvent>::iterator i = gestures->begin(); - i != gestures->end(); - ++i) { - if ((*i)->type() == ui::ET_GESTURE_SWIPE && - state_ == GESTURE_IN_PROGRESS) { - OnSwipeEvent(*i); - // The tap timer to leave gesture state is ended, and we now wait for - // all fingers to be released. - tap_timer_.Stop(); - SET_STATE(WAIT_FOR_NO_FINGERS); - return; - } - if (state_ == SLIDE_GESTURE && (*i)->IsScrollGestureEvent()) { - SideSlideControl(*i); - } + std::vector<std::unique_ptr<GestureEvent>> gestures = + gesture_provider_->GetAndResetPendingGestures(); + for (const auto& gesture : gestures) { + if (gesture->type() == ui::ET_GESTURE_SWIPE && + state_ == GESTURE_IN_PROGRESS) { + OnSwipeEvent(gesture.get()); + // The tap timer to leave gesture state is ended, and we now wait for + // all fingers to be released. + tap_timer_.Stop(); + SET_STATE(WAIT_FOR_NO_FINGERS); + return; + } + if (state_ == SLIDE_GESTURE && gesture->IsScrollGestureEvent()) { + SideSlideControl(gesture.get()); } } }
diff --git a/ui/events/event_target_iterator.h b/ui/events/event_target_iterator.h index fe3eca6c..ae83b828 100644 --- a/ui/events/event_target_iterator.h +++ b/ui/events/event_target_iterator.h
@@ -5,6 +5,7 @@ #ifndef UI_EVENTS_EVENT_TARGET_ITERATOR_H_ #define UI_EVENTS_EVENT_TARGET_ITERATOR_H_ +#include <memory> #include <vector> namespace ui { @@ -18,21 +19,19 @@ virtual EventTarget* GetNextTarget() = 0; }; -// Provides an EventTargetIterator implementation for iterating over a list of +// Provides EventTargetIterator implementations for iterating over a list of // EventTargets. The list is iterated in the reverse order, since typically the // EventTargets are maintained in increasing z-order in the lists. -template<typename T> -class EventTargetIteratorImpl : public EventTargetIterator { +template <typename T> +class EventTargetIteratorPtrImpl : public EventTargetIterator { public: - explicit EventTargetIteratorImpl(const std::vector<T*>& children) - : begin_(children.rbegin()), - end_(children.rend()) { - } - ~EventTargetIteratorImpl() override {} + explicit EventTargetIteratorPtrImpl(const std::vector<T*>& children) + : begin_(children.rbegin()), end_(children.rend()) {} + ~EventTargetIteratorPtrImpl() override {} EventTarget* GetNextTarget() override { if (begin_ == end_) - return NULL; + return nullptr; EventTarget* target = *(begin_); ++begin_; return target; @@ -43,6 +42,27 @@ typename std::vector<T*>::const_reverse_iterator end_; }; +template <typename T> +class EventTargetIteratorUniquePtrImpl : public EventTargetIterator { + public: + explicit EventTargetIteratorUniquePtrImpl( + const std::vector<std::unique_ptr<T>>& children) + : begin_(children.rbegin()), end_(children.rend()) {} + ~EventTargetIteratorUniquePtrImpl() override {} + + EventTarget* GetNextTarget() override { + if (begin_ == end_) + return nullptr; + EventTarget* target = begin_->get(); + ++begin_; + return target; + } + + private: + typename std::vector<std::unique_ptr<T>>::const_reverse_iterator begin_; + typename std::vector<std::unique_ptr<T>>::const_reverse_iterator end_; +}; + } // namespace ui #endif // UI_EVENTS_EVENT_TARGET_ITERATOR_H_
diff --git a/ui/events/gesture_detection/motion_event_buffer.cc b/ui/events/gesture_detection/motion_event_buffer.cc index d75c621..b2ce72f9 100644 --- a/ui/events/gesture_detection/motion_event_buffer.cc +++ b/ui/events/gesture_detection/motion_event_buffer.cc
@@ -6,6 +6,8 @@ #include <stddef.h> +#include <algorithm> +#include <iterator> #include <utility> #include "base/trace_event/trace_event.h" @@ -27,7 +29,7 @@ // the last time delta. const int kResampleMaxPredictionMs = 8; -typedef ScopedVector<MotionEventGeneric> MotionEventVector; +using MotionEventVector = std::vector<std::unique_ptr<MotionEventGeneric>>; float Lerp(float a, float b, float alpha) { return a + alpha * (b - a); @@ -59,34 +61,20 @@ tool == MotionEvent::TOOL_TYPE_FINGER; } -size_t CountSamplesNoLaterThan(const MotionEventVector& batch, - base::TimeTicks time) { - size_t count = 0; - while (count < batch.size() && batch[count]->GetEventTime() <= time) - ++count; - return count; -} - +// Splits a chunk of events from the front of the provided |batch| and returns +// it. Requires that |batch| is sorted. MotionEventVector ConsumeSamplesNoLaterThan(MotionEventVector* batch, base::TimeTicks time) { DCHECK(batch); - size_t count = CountSamplesNoLaterThan(*batch, time); - DCHECK_GE(batch->size(), count); - if (count == 0) - return MotionEventVector(); - - if (count == batch->size()) - return std::move(*batch); - - // TODO(jdduke): Use a ScopedDeque to work around this mess. - MotionEventVector unconsumed_batch; - unconsumed_batch.insert( - unconsumed_batch.begin(), batch->begin() + count, batch->end()); - batch->weak_erase(batch->begin() + count, batch->end()); - - unconsumed_batch.swap(*batch); - DCHECK_GE(unconsumed_batch.size(), 1U); - return unconsumed_batch; + auto first_kept_event = std::partition_point( + batch->begin(), batch->end(), + [time](const std::unique_ptr<MotionEventGeneric>& event) { + return event->GetEventTime() <= time; + }); + MotionEventVector result(std::make_move_iterator(batch->begin()), + std::make_move_iterator(first_kept_event)); + batch->erase(batch->begin(), first_kept_event); + return result; } // Linearly interpolate the pointer position between two MotionEvent samples. @@ -158,10 +146,10 @@ // Events must be in non-decreasing (time) order. std::unique_ptr<MotionEventGeneric> ConsumeSamples(MotionEventVector events) { DCHECK(!events.empty()); - std::unique_ptr<MotionEventGeneric> event(events.back()); - for (size_t i = 0; i + 1 < events.size(); ++i) - event->PushHistoricalEvent(std::unique_ptr<MotionEvent>(events[i])); - events.weak_clear(); + std::unique_ptr<MotionEventGeneric> event = std::move(events.back()); + events.pop_back(); + for (auto& historic_event : events) + event->PushHistoricalEvent(std::move(historic_event)); return event; } @@ -183,12 +171,12 @@ if (next) { DCHECK(resample_time < next->GetEventTime()); // Interpolate between current sample and future sample. - event0 = events.back(); + event0 = events.back().get(); event1 = next; } else if (events.size() >= 2) { // Extrapolate future sample using current sample and past sample. - event0 = events[events.size() - 2]; - event1 = events[events.size() - 1]; + event0 = events[events.size() - 2].get(); + event1 = events[events.size() - 1].get(); const base::TimeTicks time1 = event1->GetEventTime(); base::TimeTicks max_predict = @@ -228,10 +216,8 @@ std::unique_ptr<MotionEventGeneric> resampled_event = ResampleMotionEvent(*event0, *event1, resample_time); - for (size_t i = 0; i < events.size(); ++i) - resampled_event->PushHistoricalEvent( - std::unique_ptr<MotionEvent>(events[i])); - events.weak_clear(); + for (auto& historic_event : events) + resampled_event->PushHistoricalEvent(std::move(historic_event)); return resampled_event; } @@ -273,6 +259,7 @@ } if (CanAddSample(*buffered_events_.front(), *clone)) { + // Ensure that buffered_events_ is ordered. DCHECK(buffered_events_.back()->GetEventTime() <= clone->GetEventTime()); } else { FlushWithoutResampling(std::move(buffered_events_)); @@ -293,8 +280,8 @@ // TODO(jdduke): Use a persistent MotionEventVector vector for temporary // storage. - MotionEventVector events( - ConsumeSamplesNoLaterThan(&buffered_events_, frame_time)); + MotionEventVector events = + ConsumeSamplesNoLaterThan(&buffered_events_, frame_time); if (events.empty()) { DCHECK(!buffered_events_.empty()); client_->SetNeedsFlush(); @@ -316,7 +303,7 @@ DCHECK(!events.empty()); base::TimeTicks original_event_time = events.back()->GetEventTime(); const MotionEvent* next_event = - !buffered_events_.empty() ? buffered_events_.front() : nullptr; + !buffered_events_.empty() ? buffered_events_.front().get() : nullptr; std::unique_ptr<MotionEventGeneric> resampled_event = ConsumeSamplesAndTryResampling(resample_time, std::move(events),
diff --git a/ui/events/gesture_detection/motion_event_buffer.h b/ui/events/gesture_detection/motion_event_buffer.h index 9eb1c4c..68a8449 100644 --- a/ui/events/gesture_detection/motion_event_buffer.h +++ b/ui/events/gesture_detection/motion_event_buffer.h
@@ -6,9 +6,9 @@ #define UI_EVENTS_GESTURE_DETECTION_MOTION_EVENT_BUFFER_H_ #include <memory> +#include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/time/time.h" #include "ui/events/gesture_detection/gesture_detection_export.h" @@ -55,13 +55,15 @@ void Flush(base::TimeTicks frame_time); private: - typedef ScopedVector<MotionEventGeneric> MotionEventVector; + using MotionEventVector = std::vector<std::unique_ptr<MotionEventGeneric>>; void FlushWithResampling(MotionEventVector events, base::TimeTicks resample_time); void FlushWithoutResampling(MotionEventVector events); MotionEventBufferClient* const client_; + + // An ordered vector of buffered events. MotionEventVector buffered_events_; // Time of the most recently extrapolated event. This will be 0 if the
diff --git a/ui/events/gesture_detection/motion_event_buffer_unittest.cc b/ui/events/gesture_detection/motion_event_buffer_unittest.cc index bae3499..a128574b 100644 --- a/ui/events/gesture_detection/motion_event_buffer_unittest.cc +++ b/ui/events/gesture_detection/motion_event_buffer_unittest.cc
@@ -46,7 +46,7 @@ // MotionEventBufferClient implementation. void ForwardMotionEvent(const MotionEvent& event) override { - forwarded_events_.push_back(event.Clone().release()); + forwarded_events_.push_back(event.Clone()); } void SetNeedsFlush() override { needs_flush_ = true; } @@ -57,14 +57,14 @@ return needs_flush; } - ScopedVector<MotionEvent> GetAndResetForwardedEvents() { - ScopedVector<MotionEvent> forwarded_events; + std::vector<std::unique_ptr<MotionEvent>> GetAndResetForwardedEvents() { + std::vector<std::unique_ptr<MotionEvent>> forwarded_events; forwarded_events.swap(forwarded_events_); return forwarded_events; } const MotionEvent* GetLastEvent() const { - return forwarded_events_.empty() ? NULL : forwarded_events_.back(); + return forwarded_events_.empty() ? nullptr : forwarded_events_.back().get(); } static base::TimeDelta LargeDelta() { @@ -241,7 +241,7 @@ } private: - ScopedVector<MotionEvent> forwarded_events_; + std::vector<std::unique_ptr<MotionEvent>> forwarded_events_; bool needs_flush_; }; @@ -299,7 +299,8 @@ // The flushed events should include the up and the moves, with the latter // combined into a single event with history. - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(2U, events.size()); EXPECT_EVENT_EQ(up, *events.back()); EXPECT_EQ(2U, events.front()->GetHistorySize()); @@ -340,7 +341,8 @@ // The flushed event should only include the latest move event. buffer.Flush(event_time); - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(3U, events.size()); EXPECT_EVENT_EQ(move2, *events.back()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -438,7 +440,8 @@ buffer.Flush(flush_time); EXPECT_FALSE(GetAndResetNeedsFlush()); ASSERT_TRUE(GetLastEvent()); - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EVENT_IGNORING_HISTORY_EQ(move1, *events.front()); EXPECT_EVENT_HISTORY_EQ(*events.front(), 0, move0); @@ -526,7 +529,8 @@ // There should only be one flushed event, with the second remaining buffered // and no resampling having occurred. - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EVENT_EQ(move0, *events.front()); @@ -594,7 +598,8 @@ // the two events. base::TimeTicks expected_time = move1.GetEventTime() + (move1.GetEventTime() - move0.GetEventTime()) / 2; - ScopedVector<MotionEvent> events0 = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events0 = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events0.size()); EXPECT_EQ(2U, events0.front()->GetHistorySize()); EXPECT_EQ(expected_time, events0.front()->GetEventTime()); @@ -619,7 +624,8 @@ flush_time = event_time + ResampleDelta(); buffer.Flush(flush_time); ASSERT_TRUE(GetLastEvent()); - ScopedVector<MotionEvent> events1 = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events1 = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events1.size()); EXPECT_EVENT_EQ(move3, *events1.front()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -648,7 +654,8 @@ // There should only be one flushed event, and no resampling should have // occured between the first and the second as they were temporally too close. - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EQ(1U, events.front()->GetHistorySize()); EXPECT_EVENT_IGNORING_HISTORY_EQ(*events.front(), move1); @@ -678,7 +685,8 @@ // There should only be one flushed event, and no resampling should have // occured between the first and the second as they were temporally too close. - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EQ(1U, events.front()->GetHistorySize()); EXPECT_EVENT_IGNORING_HISTORY_EQ(*events.front(), move1); @@ -718,7 +726,8 @@ interpolated_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * alpha); - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EQ(1U, events.front()->GetHistorySize()); EXPECT_EVENT_IGNORING_HISTORY_EQ(*events.front(), interpolated_event); @@ -770,7 +779,8 @@ expected_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * expected_alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * expected_alpha); - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EQ(2U, events.front()->GetHistorySize()); EXPECT_EVENT_IGNORING_HISTORY_EQ(*events.front(), extrapolated_event); @@ -815,7 +825,8 @@ expected_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * expected_alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * expected_alpha); - ScopedVector<MotionEvent> events = GetAndResetForwardedEvents(); + std::vector<std::unique_ptr<MotionEvent>> events = + GetAndResetForwardedEvents(); ASSERT_EQ(1U, events.size()); EXPECT_EQ(2U, events.front()->GetHistorySize()); EXPECT_EVENT_IGNORING_HISTORY_EQ(*events.front(), extrapolated_event);
diff --git a/ui/events/gesture_detection/motion_event_generic.h b/ui/events/gesture_detection/motion_event_generic.h index 3b754e6..3a90b80 100644 --- a/ui/events/gesture_detection/motion_event_generic.h +++ b/ui/events/gesture_detection/motion_event_generic.h
@@ -9,7 +9,6 @@ #include <stdint.h> #include "base/containers/stack_container.h" -#include "base/memory/scoped_vector.h" #include "ui/events/gesture_detection/gesture_detection_export.h" #include "ui/events/gesture_detection/motion_event.h" @@ -127,7 +126,7 @@ int button_state_; int flags_; base::StackVector<PointerProperties, kTypicalMaxPointerCount> pointers_; - ScopedVector<MotionEvent> historical_events_; + std::vector<std::unique_ptr<MotionEvent>> historical_events_; }; } // namespace ui
diff --git a/ui/events/gestures/gesture_provider_aura.cc b/ui/events/gestures/gesture_provider_aura.cc index 1e14dcbb..e154e4b 100644 --- a/ui/events/gestures/gesture_provider_aura.cc +++ b/ui/events/gestures/gesture_provider_aura.cc
@@ -61,19 +61,15 @@ // Dispatching event caused by timer. client_->OnGestureEvent(gesture_consumer_, event.get()); } else { - // Memory managed by ScopedVector pending_gestures_. pending_gestures_.push_back(std::move(event)); } } -ScopedVector<GestureEvent>* GestureProviderAura::GetAndResetPendingGestures() { - if (pending_gestures_.empty()) - return NULL; - // Caller is responsible for deleting old_pending_gestures. - ScopedVector<GestureEvent>* old_pending_gestures = - new ScopedVector<GestureEvent>(); - old_pending_gestures->swap(pending_gestures_); - return old_pending_gestures; +std::vector<std::unique_ptr<GestureEvent>> +GestureProviderAura::GetAndResetPendingGestures() { + std::vector<std::unique_ptr<GestureEvent>> result; + result.swap(pending_gestures_); + return result; } void GestureProviderAura::OnTouchEnter(int pointer_id, float x, float y) {
diff --git a/ui/events/gestures/gesture_provider_aura.h b/ui/events/gestures/gesture_provider_aura.h index c0e397b..4fa90ac 100644 --- a/ui/events/gestures/gesture_provider_aura.h +++ b/ui/events/gestures/gesture_provider_aura.h
@@ -7,8 +7,10 @@ #include <stdint.h> +#include <memory> +#include <vector> + #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/events/event.h" #include "ui/events/events_export.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" @@ -42,7 +44,7 @@ bool OnTouchEvent(TouchEvent* event); void OnTouchEventAck(uint32_t unique_touch_event_id, bool event_consumed); const MotionEventAura& pointer_state() { return pointer_state_; } - ScopedVector<GestureEvent>* GetAndResetPendingGestures(); + std::vector<std::unique_ptr<GestureEvent>> GetAndResetPendingGestures(); void OnTouchEnter(int pointer_id, float x, float y); // GestureProviderClient implementation @@ -54,7 +56,7 @@ FilteredGestureProvider filtered_gesture_provider_; bool handling_event_; - ScopedVector<GestureEvent> pending_gestures_; + std::vector<std::unique_ptr<GestureEvent>> pending_gestures_; // |gesture_consumer_| must outlive this object. GestureConsumer* gesture_consumer_;
diff --git a/ui/events/gestures/gesture_recognizer.h b/ui/events/gestures/gesture_recognizer.h index bc20699..4f3daf4 100644 --- a/ui/events/gestures/gesture_recognizer.h +++ b/ui/events/gestures/gesture_recognizer.h
@@ -7,9 +7,9 @@ #include <stdint.h> +#include <memory> #include <vector> -#include "base/memory/scoped_vector.h" #include "ui/events/event_constants.h" #include "ui/events/events_export.h" #include "ui/events/gestures/gesture_types.h" @@ -24,8 +24,7 @@ static GestureRecognizer* Get(); static void Reset(); - // List of GestureEvent*. - typedef ScopedVector<GestureEvent> Gestures; + using Gestures = std::vector<std::unique_ptr<GestureEvent>>; virtual ~GestureRecognizer() {} @@ -34,12 +33,11 @@ virtual bool ProcessTouchEventPreDispatch(TouchEvent* event, GestureConsumer* consumer) = 0; - // Returns a list of zero or more GestureEvents. The caller is responsible for - // freeing the returned events. Acks the gesture packet in the queue which - // matches with unique_event_id. - virtual Gestures* AckTouchEvent(uint32_t unique_event_id, - ui::EventResult result, - GestureConsumer* consumer) = 0; + // Returns a list of zero or more GestureEvents. Acks the gesture packet in + // the queue which matches with unique_event_id. + virtual Gestures AckTouchEvent(uint32_t unique_event_id, + ui::EventResult result, + GestureConsumer* consumer) = 0; // This is called when the consumer is destroyed. So this should cleanup any // internal state maintained for |consumer|. Returns true iff there was
diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc index 9bd655d2e..bc0776b 100644 --- a/ui/events/gestures/gesture_recognizer_impl.cc +++ b/ui/events/gestures/gesture_recognizer_impl.cc
@@ -273,7 +273,7 @@ return gesture_provider->OnTouchEvent(event); } -GestureRecognizer::Gestures* GestureRecognizerImpl::AckTouchEvent( +GestureRecognizer::Gestures GestureRecognizerImpl::AckTouchEvent( uint32_t unique_event_id, ui::EventResult result, GestureConsumer* consumer) {
diff --git a/ui/events/gestures/gesture_recognizer_impl.h b/ui/events/gestures/gesture_recognizer_impl.h index aabda346..a3e0f573 100644 --- a/ui/events/gestures/gesture_recognizer_impl.h +++ b/ui/events/gestures/gesture_recognizer_impl.h
@@ -70,9 +70,9 @@ bool ProcessTouchEventPreDispatch(TouchEvent* event, GestureConsumer* consumer) override; - Gestures* AckTouchEvent(uint32_t unique_event_id, - ui::EventResult result, - GestureConsumer* consumer) override; + Gestures AckTouchEvent(uint32_t unique_event_id, + ui::EventResult result, + GestureConsumer* consumer) override; bool CleanupStateForConsumer(GestureConsumer* consumer) override; void AddGestureEventHelper(GestureEventHelper* helper) override;
diff --git a/ui/events/gestures/gesture_recognizer_impl_mac.cc b/ui/events/gestures/gesture_recognizer_impl_mac.cc index 73e3cdc9..d3036c7 100644 --- a/ui/events/gestures/gesture_recognizer_impl_mac.cc +++ b/ui/events/gestures/gesture_recognizer_impl_mac.cc
@@ -5,6 +5,7 @@ #include <stdint.h> #include "base/macros.h" +#include "ui/events/event.h" #include "ui/events/gestures/gesture_recognizer.h" namespace ui { @@ -24,10 +25,10 @@ return false; } - Gestures* AckTouchEvent(uint32_t unique_event_id, - ui::EventResult result, - GestureConsumer* consumer) override { - return NULL; + Gestures AckTouchEvent(uint32_t unique_event_id, + ui::EventResult result, + GestureConsumer* consumer) override { + return {}; } bool CleanupStateForConsumer(GestureConsumer* consumer) override { return false;
diff --git a/ui/events/platform/platform_event_source_unittest.cc b/ui/events/platform/platform_event_source_unittest.cc index e2d87c067..9ef8bc5e 100644 --- a/ui/events/platform/platform_event_source_unittest.cc +++ b/ui/events/platform/platform_event_source_unittest.cc
@@ -9,10 +9,11 @@ #include <memory> #include <utility> +#include <vector> #include "base/bind.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" @@ -26,14 +27,11 @@ namespace { std::unique_ptr<PlatformEvent> CreatePlatformEvent() { - std::unique_ptr<PlatformEvent> event(new PlatformEvent()); + std::unique_ptr<PlatformEvent> event = base::MakeUnique<PlatformEvent>(); memset(event.get(), 0, sizeof(PlatformEvent)); return event; } -template <typename T> -void DestroyScopedPtr(std::unique_ptr<T> object) {} - void RemoveDispatcher(PlatformEventDispatcher* dispatcher) { PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(dispatcher); } @@ -61,7 +59,8 @@ // Dispatches the stream of events, and returns the number of events that are // dispatched before it is requested to stop. - size_t DispatchEventStream(const ScopedVector<PlatformEvent>& events) { + size_t DispatchEventStream( + const std::vector<std::unique_ptr<PlatformEvent>>& events) { stop_stream_ = false; for (size_t count = 0; count < events.size(); ++count) { DispatchEvent(*events[count]); @@ -157,13 +156,13 @@ // Tests that a dispatcher receives an event. TEST_F(PlatformEventTest, DispatcherBasic) { std::vector<int> list_dispatcher; - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); EXPECT_EQ(0u, list_dispatcher.size()); { TestPlatformEventDispatcher dispatcher(1, &list_dispatcher); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(1u, list_dispatcher.size()); EXPECT_EQ(1, list_dispatcher[0]); @@ -179,12 +178,12 @@ TEST_F(PlatformEventTest, DispatcherOrder) { std::vector<int> list_dispatcher; int sequence[] = {21, 3, 6, 45}; - ScopedVector<TestPlatformEventDispatcher> dispatchers; - for (size_t i = 0; i < arraysize(sequence); ++i) { + std::vector<std::unique_ptr<TestPlatformEventDispatcher>> dispatchers; + for (auto id : sequence) { dispatchers.push_back( - new TestPlatformEventDispatcher(sequence[i], &list_dispatcher)); + base::MakeUnique<TestPlatformEventDispatcher>(id, &list_dispatcher)); } - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(arraysize(sequence), list_dispatcher.size()); EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)), @@ -198,7 +197,7 @@ TestPlatformEventDispatcher first(12, &list_dispatcher); TestPlatformEventDispatcher second(23, &list_dispatcher); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list_dispatcher.size()); EXPECT_EQ(12, list_dispatcher[0]); @@ -215,13 +214,13 @@ // Tests that observers receive events. TEST_F(PlatformEventTest, ObserverBasic) { std::vector<int> list_observer; - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); EXPECT_EQ(0u, list_observer.size()); { TestPlatformEventObserver observer(31, &list_observer); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(1u, list_observer.size()); EXPECT_EQ(31, list_observer[0]); @@ -237,12 +236,12 @@ TEST_F(PlatformEventTest, ObserverOrder) { std::vector<int> list_observer; const int sequence[] = {21, 3, 6, 45}; - ScopedVector<TestPlatformEventObserver> observers; - for (size_t i = 0; i < arraysize(sequence); ++i) { + std::vector<std::unique_ptr<TestPlatformEventObserver>> observers; + for (auto id : sequence) { observers.push_back( - new TestPlatformEventObserver(sequence[i], &list_observer)); + base::MakeUnique<TestPlatformEventObserver>(id, &list_observer)); } - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(arraysize(sequence), list_observer.size()); EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)), @@ -256,7 +255,7 @@ TestPlatformEventObserver first_o(10, &list); TestPlatformEventDispatcher second_d(23, &list); TestPlatformEventObserver second_o(20, &list); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); const int expected[] = {10, 20, 12, 23}; EXPECT_EQ(std::vector<int>(expected, expected + arraysize(expected)), list); @@ -268,7 +267,7 @@ std::vector<int> list; TestPlatformEventDispatcher dispatcher(10, &list); TestPlatformEventObserver observer(15, &list); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list.size()); EXPECT_EQ(15, list[0]); @@ -297,7 +296,7 @@ source()->OverrideDispatcher(&overriding_dispatcher); overriding_dispatcher.set_post_dispatch_action(POST_DISPATCH_PERFORM_DEFAULT); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // First the observer, then the overriding dispatcher, then the default // dispatcher. @@ -365,7 +364,7 @@ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&third))); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // |second| removes |third| from the dispatcher list during dispatch. So the // event should only reach |first|, |second|, and |fourth|. @@ -385,7 +384,7 @@ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second))); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // |second| removes itself from the dispatcher list during dispatch. So the // event should reach all three dispatchers in the list. @@ -405,7 +404,7 @@ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second))); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // |second| removes itself during dispatch. So both dispatchers will have // received the event. @@ -424,7 +423,7 @@ second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&first))); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // |second| removes |first| from the dispatcher list during dispatch. The // event should reach all three dispatchers. @@ -447,7 +446,7 @@ base::Unretained(&first), base::Unretained(&second))); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); // |third| removes |first| and |second| from the dispatcher list during // dispatch. The event should reach all three dispatchers. @@ -468,7 +467,7 @@ TestPlatformEventDispatcher fourth(30, &list); RemoveDispatchers(&third, &fourth); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list.size()); EXPECT_EQ(10, list[0]); @@ -539,7 +538,7 @@ std::unique_ptr<ScopedEventDispatcher> second_override_handle = source()->OverrideDispatcher(&second_overriding); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list.size()); EXPECT_EQ(15, list[0]); @@ -600,11 +599,9 @@ public: void NestedTask(std::vector<int>* list, TestPlatformEventDispatcher* dispatcher) { - ScopedVector<PlatformEvent> events; - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); - events.push_back(std::move(event)); - event = CreatePlatformEvent(); - events.push_back(std::move(event)); + std::vector<std::unique_ptr<PlatformEvent>> events; + events.push_back(CreatePlatformEvent()); + events.push_back(CreatePlatformEvent()); // Attempt to dispatch a couple of events. Dispatching the first event will // have terminated the ScopedEventDispatcher object, which will terminate @@ -641,7 +638,7 @@ std::unique_ptr<ScopedEventDispatcher> override_handle = source()->OverrideDispatcher(&overriding); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list.size()); EXPECT_EQ(15, list[0]); @@ -682,7 +679,7 @@ public: void NestedTask(std::unique_ptr<ScopedEventDispatcher> dispatch_handle, std::vector<int>* list) { - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list->size()); EXPECT_EQ(15, (*list)[0]); @@ -741,7 +738,7 @@ std::unique_ptr<ScopedEventDispatcher> override_handle = source()->OverrideDispatcher(&overriding); - std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); + std::unique_ptr<PlatformEvent> event = CreatePlatformEvent(); source()->Dispatch(*event); ASSERT_EQ(2u, list.size()); EXPECT_EQ(15, list[0]);
diff --git a/ui/events/test/test_event_target.cc b/ui/events/test/test_event_target.cc index eefebed2..0445d0d 100644 --- a/ui/events/test/test_event_target.cc +++ b/ui/events/test/test_event_target.cc
@@ -25,24 +25,20 @@ TestEventTarget::~TestEventTarget() {} void TestEventTarget::AddChild(std::unique_ptr<TestEventTarget> child) { - TestEventTarget* child_r = child.get(); - if (child->parent()) { - AddChild(child->parent()->RemoveChild(child.release())); - } else { - children_.push_back(std::move(child)); - } - child_r->set_parent(this); + DCHECK(!child->parent()); + children_.push_back(std::move(child)); + children_.back()->set_parent(this); } std::unique_ptr<TestEventTarget> TestEventTarget::RemoveChild( TestEventTarget* c) { - ScopedVector<TestEventTarget>::iterator iter = std::find(children_.begin(), - children_.end(), - c); - if (iter != children_.end()) { - children_.weak_erase(iter); - c->set_parent(NULL); - return base::WrapUnique(c); + for (auto iter = children_.begin(); iter != children_.end(); ++iter) { + if (iter->get() == c) { + std::unique_ptr<TestEventTarget> child = std::move(*iter); + children_.erase(iter); + child->set_parent(nullptr); + return child; + } } return nullptr; } @@ -72,8 +68,8 @@ } std::unique_ptr<EventTargetIterator> TestEventTarget::GetChildIterator() const { - return base::MakeUnique<EventTargetIteratorImpl<TestEventTarget>>( - children_.get()); + return base::MakeUnique<EventTargetIteratorUniquePtrImpl<TestEventTarget>>( + children_); } EventTargeter* TestEventTarget::GetEventTargeter() {
diff --git a/ui/events/test/test_event_target.h b/ui/events/test/test_event_target.h index 3b5311d..9e9af656 100644 --- a/ui/events/test/test_event_target.h +++ b/ui/events/test/test_event_target.h
@@ -7,12 +7,12 @@ #include <stddef.h> +#include <memory> #include <set> #include <string> #include <vector> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "ui/events/event_target.h" typedef std::vector<std::string> HandlerSequenceRecorder; @@ -35,7 +35,7 @@ mark_events_as_handled_ = handle; } - TestEventTarget* child_at(int index) { return children_[index]; } + TestEventTarget* child_at(int index) { return children_[index].get(); } size_t child_count() const { return children_.size(); } void SetEventTargeter(std::unique_ptr<EventTargeter> targeter); @@ -68,7 +68,7 @@ void set_parent(TestEventTarget* parent) { parent_ = parent; } TestEventTarget* parent_; - ScopedVector<TestEventTarget> children_; + std::vector<std::unique_ptr<TestEventTarget>> children_; std::unique_ptr<EventTargeter> targeter_; bool mark_events_as_handled_;
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc index 674685b..638bd29f 100644 --- a/ui/keyboard/keyboard_controller.cc +++ b/ui/keyboard/keyboard_controller.cc
@@ -283,14 +283,7 @@ if (keyboard_mode_ == FLOATING) { NotifyKeyboardBoundsChanging(gfx::Rect()); } else if (keyboard_mode_ == FULL_WIDTH) { - // TODO(bshe): revisit this logic after we decide to support resize virtual - // keyboard. - int keyboard_height = GetContainerWindow()->bounds().height(); - const gfx::Rect& root_bounds = container_->GetRootWindow()->bounds(); - gfx::Rect new_bounds = root_bounds; - new_bounds.set_y(root_bounds.height() - keyboard_height); - new_bounds.set_height(keyboard_height); - GetContainerWindow()->SetBounds(new_bounds); + AdjustKeyboardBounds(); // No animation added, so call ShowAnimationFinished immediately. ShowAnimationFinished(); } @@ -319,6 +312,7 @@ void KeyboardController::OnWindowAddedToRootWindow(aura::Window* window) { if (!window->GetRootWindow()->HasObserver(this)) window->GetRootWindow()->AddObserver(this); + AdjustKeyboardBounds(); } void KeyboardController::OnWindowRemovingFromRootWindow(aura::Window* window, @@ -511,4 +505,21 @@ observer.OnKeyboardHidden(); } +void KeyboardController::AdjustKeyboardBounds() { + // When keyboard is floating, no resize is necessary. + if (keyboard_mode_ == FLOATING) + return; + + if (keyboard_mode_ == FULL_WIDTH) { + // TODO(bshe): revisit this logic after we decide to support resize virtual + // keyboard. + int keyboard_height = GetContainerWindow()->bounds().height(); + const gfx::Rect& root_bounds = container_->GetRootWindow()->bounds(); + gfx::Rect new_bounds = root_bounds; + new_bounds.set_y(root_bounds.height() - keyboard_height); + new_bounds.set_height(keyboard_height); + GetContainerWindow()->SetBounds(new_bounds); + } +} + } // namespace keyboard
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h index 817fa0d..2bfe473f 100644 --- a/ui/keyboard/keyboard_controller.h +++ b/ui/keyboard/keyboard_controller.h
@@ -159,6 +159,10 @@ void ShowAnimationFinished(); void HideAnimationFinished(); + // Called when the keyboard mode is set or the keyboard is moved to another + // display. + void AdjustKeyboardBounds(); + std::unique_ptr<KeyboardUI> ui_; KeyboardLayoutDelegate* layout_delegate_; std::unique_ptr<aura::Window> container_;
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc index c2b47f3c..147c6df0 100644 --- a/ui/keyboard/keyboard_controller_unittest.cc +++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -299,7 +299,8 @@ const gfx::Rect& initial_bounds = container->bounds(); // The container should be positioned at the bottom of screen and has 0 // height. - ASSERT_EQ(gfx::Rect(), initial_bounds); + ASSERT_EQ(0, initial_bounds.height()); + ASSERT_EQ(screen_bounds.height(), initial_bounds.y()); VerifyKeyboardWindowSize(container, keyboard); // In FULL_WIDTH mode, attempt to change window width or move window up from @@ -328,6 +329,38 @@ VerifyKeyboardWindowSize(container, keyboard); } +TEST_F(KeyboardControllerTest, KeyboardSizeMultiRootWindow) { + aura::Window* container(controller()->GetContainerWindow()); + aura::Window* keyboard(ui()->GetKeyboardWindow()); + gfx::Rect screen_bounds = root_window()->bounds(); + root_window()->AddChild(container); + container->AddChild(keyboard); + const gfx::Rect& initial_bounds = container->bounds(); + // The container should be positioned at the bottom of screen and has 0 + // height. + ASSERT_EQ(0, initial_bounds.height()); + ASSERT_EQ(screen_bounds.height(), initial_bounds.y()); + VerifyKeyboardWindowSize(container, keyboard); + + // Adding new root window. + std::unique_ptr<aura::WindowTreeHost> secondary_tree_host = + base::WrapUnique<aura::WindowTreeHost>( + aura::WindowTreeHost::Create(gfx::Rect(0, 0, 1000, 500))); + secondary_tree_host->InitHost(); + EXPECT_EQ(1000, secondary_tree_host->window()->bounds().width()); + EXPECT_EQ(500, secondary_tree_host->window()->bounds().height()); + + // Move the keyboard into the secondary root window. + controller()->HideKeyboard( + KeyboardController::HideReason::HIDE_REASON_AUTOMATIC); + root_window()->RemoveChild(container); + secondary_tree_host->window()->AddChild(container); + + const gfx::Rect& new_bounds = container->bounds(); + EXPECT_EQ(500, new_bounds.y()); + VerifyKeyboardWindowSize(container, keyboard); +} + TEST_F(KeyboardControllerTest, FloatingKeyboardSize) { aura::Window* container(controller()->GetContainerWindow()); aura::Window* keyboard(ui()->GetKeyboardWindow()); @@ -567,6 +600,7 @@ root_window()->RemoveChild(keyboard_container); ResetController(); EXPECT_TRUE(IsKeyboardClosed()); + keyboard::SetAccessibilityKeyboardEnabled(false); } class KeyboardControllerAnimationTest : public KeyboardControllerTest { @@ -675,6 +709,8 @@ aura::Window* container(controller()->GetContainerWindow()); aura::Window* keyboard(ui()->GetKeyboardWindow()); root_window()->AddChild(container); + + keyboard::SetTouchKeyboardEnabled(true); controller()->SetKeyboardMode(FLOATING); container->AddChild(keyboard); // Mock focus on an input field.
diff --git a/ui/login/screen_container.css b/ui/login/screen_container.css index 6e0fcfe..2dd778817 100644 --- a/ui/login/screen_container.css +++ b/ui/login/screen_container.css
@@ -19,6 +19,7 @@ .oobe-display #outer-container { -webkit-perspective: 600px; + bottom: 47px; /* header-bar is 47 pixels high during OOBE */ } .pin-container.pin-enabled { @@ -66,6 +67,19 @@ pointer-events: none; } +#oobe-shield { + display: none; +} + +#oobe-shield[md-mode] { + background-color: rgba(20, 29, 40, .8); /* #141D28 80% */ + display: block; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} #oobe[md-mode] #progress-dots { display: none;
diff --git a/ui/views/view.cc b/ui/views/view.cc index 48f3fbbe..d65f4bc 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -1158,7 +1158,7 @@ } std::unique_ptr<ui::EventTargetIterator> View::GetChildIterator() const { - return base::MakeUnique<ui::EventTargetIteratorImpl<View>>(children_); + return base::MakeUnique<ui::EventTargetIteratorPtrImpl<View>>(children_); } ui::EventTargeter* View::GetEventTargeter() {