diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4ec2818..791d86e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md
@@ -2,9 +2,10 @@ Google and the Chromium team are committed to preserving and fostering a diverse, welcoming community. Below is our community code of conduct, which -applies to our repos and organizations, mailing lists, blog content, and any -other Chromium-supported communication group, as well as any private -communication initiated in the context of these spaces. +applies to our repos and organizations, issue trackers, mailing lists, +blog content, and any other Chromium-supported communication group, as +well as any private communication initiated in the context of these +spaces. Simply put, community discussions should be
diff --git a/DEPS b/DEPS index da08fa4d..9618dd5 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': 'bb581ce30f55360fd3a12e7f5aa1fe324b16d085', + 'skia_revision': 'b474e2d826cf7d6ac232d1e39c61e02c472e43b6', # 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': '22670b3d2406d02f0bc4dfe423ab20ad9050f8e1', + 'v8_revision': '7a0544bebdaf63502786de341fd167ba1a002cd0', # 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. @@ -52,7 +52,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '7d79fe95bd353a9ca0805db7d7b6442b3c5e7469', + 'angle_revision': '63d8c2662c284955459eccbf7f40fcf8a8f51651', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # 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': '207b7277775a2194494352b154109bfa13dd5032', + 'pdfium_revision': 'b58ff22b729a9b141a7d735254ffa2cbf3ce2b22', # 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.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 8a81bb0..c88f315 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -204,6 +204,7 @@ r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$", r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]" "customization_document_browsertest\.cc$", + r"^chrome[\\\/]test[\\\/]ppapi[\\\/]ppapi_filechooser_browsertest\.cc$", r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$", r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" + r"test_info_extractor\.cc$",
diff --git a/base/metrics/persistent_memory_allocator.cc b/base/metrics/persistent_memory_allocator.cc index deb82ac..f569efa 100644 --- a/base/metrics/persistent_memory_allocator.cc +++ b/base/metrics/persistent_memory_allocator.cc
@@ -162,6 +162,11 @@ } void PersistentMemoryAllocator::Iterator::Reset(Reference starting_after) { + if (starting_after == 0) { + Reset(); + return; + } + last_record_.store(starting_after, std::memory_order_relaxed); record_count_.store(0, std::memory_order_relaxed);
diff --git a/base/metrics/persistent_memory_allocator.h b/base/metrics/persistent_memory_allocator.h index b7e7bd08..79eb96d4 100644 --- a/base/metrics/persistent_memory_allocator.h +++ b/base/metrics/persistent_memory_allocator.h
@@ -494,7 +494,8 @@ // Reserve space in the memory segment of the desired |size| and |type_id|. // A return value of zero indicates the allocation failed, otherwise the // returned reference can be used by any process to get a real pointer via - // the GetAsObject() or GetAsArray calls. + // the GetAsObject() or GetAsArray calls. The actual allocated size may be + // larger and will always be a multiple of 8 bytes (64 bits). Reference Allocate(size_t size, uint32_t type_id); // Allocate and construct an object in persistent memory. The type must have
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc index d55e21b1..1215b2a3 100644 --- a/base/threading/sequenced_worker_pool.cc +++ b/base/threading/sequenced_worker_pool.cc
@@ -1545,6 +1545,13 @@ return new SequencedWorkerPoolTaskRunner(this, shutdown_behavior); } +bool SequencedWorkerPool::PostWorkerTask( + const tracked_objects::Location& from_here, + OnceClosure task) { + return inner_->PostTask(NULL, SequenceToken(), BLOCK_SHUTDOWN, from_here, + std::move(task), TimeDelta()); +} + bool SequencedWorkerPool::PostWorkerTaskWithShutdownBehavior( const tracked_objects::Location& from_here, OnceClosure task,
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h index d86760b4..043df2dd 100644 --- a/base/threading/sequenced_worker_pool.h +++ b/base/threading/sequenced_worker_pool.h
@@ -55,7 +55,7 @@ // You can make named sequence tokens to make it easier to share a token // across different components. // -// You can also post tasks to the pool without ordering using PostTask. +// You can also post tasks to the pool without ordering using PostWorkerTask. // These will be executed in an unspecified order. The order of execution // between tasks with different sequence tokens is also unspecified. // @@ -255,6 +255,29 @@ scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior( WorkerShutdown shutdown_behavior) WARN_UNUSED_RESULT; + // Posts the given task for execution in the worker pool. Tasks posted with + // this function will execute in an unspecified order on a background thread. + // Returns true if the task was posted. If your tasks have ordering + // requirements, see PostSequencedWorkerTask(). + // + // This class will attempt to delete tasks that aren't run + // (non-block-shutdown semantics) but can't guarantee that this happens. If + // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there + // will be no workers available to delete these tasks. And there may be + // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN + // tasks. Deleting those tasks before the previous one has completed could + // cause nondeterministic crashes because the task could be keeping some + // objects alive which do work in their destructor, which could voilate the + // assumptions of the running task. + // + // The task will be guaranteed to run to completion before shutdown + // (BLOCK_SHUTDOWN semantics). + // + // Returns true if the task was posted successfully. This may fail during + // shutdown regardless of the specified ShutdownBehavior. + bool PostWorkerTask(const tracked_objects::Location& from_here, + OnceClosure task); + // Same as PostWorkerTask but allows specification of the shutdown behavior. bool PostWorkerTaskWithShutdownBehavior( const tracked_objects::Location& from_here,
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc index 17eadbb3..ccc21d8 100644 --- a/base/threading/sequenced_worker_pool_unittest.cc +++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -322,8 +322,9 @@ // workers to be created. ThreadBlocker blocker; for (size_t i = 0; i < kNumWorkerThreads; i++) { - pool()->PostTask(FROM_HERE, base::BindOnce(&TestTracker::BlockTask, - tracker(), -1, &blocker)); + pool()->PostWorkerTask( + FROM_HERE, + base::BindOnce(&TestTracker::BlockTask, tracker(), -1, &blocker)); } tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); @@ -452,13 +453,13 @@ // Tests that posting a bunch of tasks (many more than the number of worker // threads) runs them all. TEST_P(SequencedWorkerPoolTest, LotsOfTasks) { - pool()->PostTask(FROM_HERE, - base::BindOnce(&TestTracker::SlowTask, tracker(), 0)); + pool()->PostWorkerTask(FROM_HERE, + base::BindOnce(&TestTracker::SlowTask, tracker(), 0)); const size_t kNumTasks = 20; for (size_t i = 1; i < kNumTasks; i++) { - pool()->PostTask(FROM_HERE, - base::BindOnce(&TestTracker::FastTask, tracker(), i)); + pool()->PostWorkerTask( + FROM_HERE, base::BindOnce(&TestTracker::FastTask, tracker(), i)); } std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks); @@ -474,15 +475,15 @@ SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2"); base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0); - pool1.pool()->PostTask(FROM_HERE, slow_task); - pool2.pool()->PostTask(FROM_HERE, slow_task); + pool1.pool()->PostWorkerTask(FROM_HERE, slow_task); + pool2.pool()->PostWorkerTask(FROM_HERE, slow_task); const size_t kNumTasks = 20; for (size_t i = 1; i < kNumTasks; i++) { base::Closure fast_task = base::Bind(&TestTracker::FastTask, tracker(), i); - pool1.pool()->PostTask(FROM_HERE, fast_task); - pool2.pool()->PostTask(FROM_HERE, fast_task); + pool1.pool()->PostWorkerTask(FROM_HERE, fast_task); + pool2.pool()->PostWorkerTask(FROM_HERE, fast_task); } std::vector<int> result = @@ -497,9 +498,9 @@ const size_t kNumBackgroundTasks = kNumWorkerThreads - 1; ThreadBlocker background_blocker; for (size_t i = 0; i < kNumBackgroundTasks; i++) { - pool()->PostTask(FROM_HERE, - base::BindOnce(&TestTracker::BlockTask, tracker(), i, - &background_blocker)); + pool()->PostWorkerTask(FROM_HERE, + base::BindOnce(&TestTracker::BlockTask, tracker(), i, + &background_blocker)); } tracker()->WaitUntilTasksBlocked(kNumBackgroundTasks); @@ -558,8 +559,8 @@ EnsureAllWorkersCreated(); ThreadBlocker blocker; for (size_t i = 0; i < kNumWorkerThreads; i++) { - pool()->PostTask(FROM_HERE, base::BindOnce(&TestTracker::BlockTask, - tracker(), i, &blocker)); + pool()->PostWorkerTask(FROM_HERE, base::BindOnce(&TestTracker::BlockTask, + tracker(), i, &blocker)); } tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); @@ -605,7 +606,7 @@ // Start tasks to take all the threads and block them. const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads); for (int i = 0; i < kNumBlockTasks; ++i) { - EXPECT_TRUE(pool()->PostTask( + EXPECT_TRUE(pool()->PostWorkerTask( FROM_HERE, base::BindOnce(&TestTracker::BlockTask, tracker(), i, &blocker))); } @@ -669,7 +670,7 @@ // Start tasks to take all the threads and block them. const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads); for (int i = 0; i < kNumBlockTasks; ++i) { - EXPECT_TRUE(pool()->PostTask( + EXPECT_TRUE(pool()->PostWorkerTask( FROM_HERE, base::BindOnce(&TestTracker::BlockTask, tracker(), i, &blocker))); } @@ -725,8 +726,8 @@ EnsureAllWorkersCreated(); ThreadBlocker blocker; for (size_t i = 0; i < kNumWorkerThreads; i++) { - pool()->PostTask(FROM_HERE, base::BindOnce(&TestTracker::BlockTask, - tracker(), i, &blocker)); + pool()->PostWorkerTask(FROM_HERE, base::BindOnce(&TestTracker::BlockTask, + tracker(), i, &blocker)); } tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); @@ -993,14 +994,14 @@ pool()->PostDelayedTask(FROM_HERE, base::BindOnce(&TestTracker::FastTask, tracker(), 0), TimeDelta::FromMinutes(5)); - pool()->PostTask(FROM_HERE, - base::BindOnce(&TestTracker::SlowTask, tracker(), 0)); + pool()->PostWorkerTask(FROM_HERE, + base::BindOnce(&TestTracker::SlowTask, tracker(), 0)); const size_t kNumFastTasks = 20; for (size_t i = 0; i < kNumFastTasks; i++) { - pool()->PostTask(FROM_HERE, - base::BindOnce(&TestTracker::FastTask, tracker(), 0)); + pool()->PostWorkerTask( + FROM_HERE, base::BindOnce(&TestTracker::FastTask, tracker(), 0)); } - pool()->PostTask( + pool()->PostWorkerTask( FROM_HERE, base::BindOnce(&TestTracker::PostAdditionalTasks, tracker(), 0, base::RetainedRef(pool()), true)); @@ -1077,9 +1078,9 @@ token2, FROM_HERE, base::BindOnce(&CheckWorkerPoolAndSequenceToken, pool(), token2)); - pool()->PostTask(FROM_HERE, - base::BindOnce(&CheckWorkerPoolAndSequenceToken, pool(), - SequencedWorkerPool::SequenceToken())); + pool()->PostWorkerTask( + FROM_HERE, base::BindOnce(&CheckWorkerPoolAndSequenceToken, pool(), + SequencedWorkerPool::SequenceToken())); pool()->FlushForTesting(); }
diff --git a/build/build_config.h b/build/build_config.h index 0906419..30c5783b 100644 --- a/build/build_config.h +++ b/build/build_config.h
@@ -160,6 +160,18 @@ #define ARCH_CPU_32_BITS 1 #define ARCH_CPU_LITTLE_ENDIAN 1 #endif +#elif defined(__MIPSEB__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#endif #else #error Please add support for your architecture in build/build_config.h #endif
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index fa4ec72c..95572936 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -139,7 +139,8 @@ current_os == "mac" || current_os == "ios" || current_os == "chromeos" || current_os == "fuchsia" || (current_os == "linux" && current_cpu != "s390x" && - current_cpu != "s390" && current_cpu != "ppc64" && current_cpu != "ppc") + current_cpu != "s390" && current_cpu != "ppc64" && + current_cpu != "ppc" && current_cpu != "mips" && current_cpu != "mips64") # Allows the path to a custom target toolchain to be injected as a single # argument, and set as the default toolchain.
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index fd079e6c..7eb4fb3f 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -13,7 +13,8 @@ if (current_cpu == "arm" || current_cpu == "arm64") { import("//build/config/arm.gni") } -if (current_cpu == "mipsel" || current_cpu == "mips64el") { +if (current_cpu == "mipsel" || current_cpu == "mips64el" || + current_cpu == "mips" || current_cpu == "mips64") { import("//build/config/mips.gni") } if (is_mac) { @@ -685,6 +686,40 @@ } cflags += [ "-m${mips_float_abi}-float" ] + } else if (current_cpu == "mips" && !is_nacl) { + if (mips_arch_variant == "r6") { + cflags += [ + "-mips32r6", + "-Wa,-mips32r6", + ] + if (mips_use_msa == true) { + cflags += [ + "-mmsa", + "-mfp64", + ] + } + } else if (mips_arch_variant == "r2") { + cflags += [ + "-mips32r2", + "-Wa,-mips32r2", + ] + if (mips_float_abi == "hard" && mips_fpu_mode != "") { + cflags += [ "-m$mips_fpu_mode" ] + } + } else if (mips_arch_variant == "r1") { + cflags += [ + "-mips32", + "-Wa,-mips32", + ] + } + + if (mips_dsp_rev == 1) { + cflags += [ "-mdsp" ] + } else if (mips_dsp_rev == 2) { + cflags += [ "-mdspr2" ] + } + + cflags += [ "-m${mips_float_abi}-float" ] } else if (current_cpu == "mips64el") { if (mips_arch_variant == "r6") { if (is_clang) { @@ -716,6 +751,26 @@ ] ldflags += [ "-mips64r2" ] } + } else if (current_cpu == "mips64") { + if (mips_arch_variant == "r6") { + cflags += [ + "-mips64r6", + "-Wa,-mips64r6", + ] + ldflags += [ "-mips64r6" ] + if (mips_use_msa == true) { + cflags += [ + "-mmsa", + "-mfp64", + ] + } + } else if (mips_arch_variant == "r2") { + cflags += [ + "-mips64r2", + "-Wa,-mips64r2", + ] + ldflags += [ "-mips64r2" ] + } } else if (current_cpu == "pnacl" && is_nacl_nonsfi) { if (target_cpu == "x86" || target_cpu == "x64") { cflags += [ @@ -1164,7 +1219,8 @@ if (!is_debug && !using_sanitizer && (!is_linux || !is_clang || is_official_build) && current_cpu != "s390x" && current_cpu != "s390" && - current_cpu != "ppc64" && current_cpu != "ppc64") { + current_cpu != "ppc64" && current_cpu != "ppc64" && + current_cpu != "mips" && current_cpu != "mips64") { # _FORTIFY_SOURCE isn't really supported by Clang now, see # http://llvm.org/bugs/show_bug.cgi?id=16821. # It seems to work fine with Ubuntu 12 headers though, so use it in
diff --git a/build/config/mips.gni b/build/config/mips.gni index 5604ca6..ca582e1 100644 --- a/build/config/mips.gni +++ b/build/config/mips.gni
@@ -8,7 +8,8 @@ # MIPS code is being compiled. But they can also be relevant in the # other contexts when the code will change its behavior based on the # cpu it wants to generate code for. -if (current_cpu == "mipsel" || v8_current_cpu == "mipsel") { +if (current_cpu == "mipsel" || v8_current_cpu == "mipsel" || + current_cpu == "mips" || v8_current_cpu == "mips") { declare_args() { # MIPS arch variant. Possible values are: # "r1" @@ -36,7 +37,8 @@ # "fpxx": sets the GCC -mfpxx option. mips_fpu_mode = "fp32" } -} else if (current_cpu == "mips64el" || v8_current_cpu == "mips64el") { +} else if (current_cpu == "mips64el" || v8_current_cpu == "mips64el" || + current_cpu == "mips64" || v8_current_cpu == "mips64") { # MIPS arch variant. Possible values are: # "r2" # "r6"
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni index 51f106e..563d2d5 100644 --- a/build/config/sysroot.gni +++ b/build/config/sysroot.gni
@@ -16,7 +16,8 @@ target_sysroot_dir = "//build/linux" use_sysroot = current_cpu != "s390x" && current_cpu != "s390" && - current_cpu != "ppc64" && current_cpu != "ppc" + current_cpu != "ppc64" && current_cpu != "ppc" && + current_cpu != "mips" && current_cpu != "mips64" } if (current_os == target_os && current_cpu == target_cpu &&
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn index 5b7689f..f099019 100644 --- a/build/toolchain/linux/BUILD.gn +++ b/build/toolchain/linux/BUILD.gn
@@ -83,6 +83,14 @@ } } +clang_toolchain("clang_x86_v8_mips") { + toolchain_args = { + current_cpu = "x86" + v8_current_cpu = "mips" + current_os = "linux" + } +} + gcc_toolchain("x86") { cc = "gcc" cxx = "g++" @@ -128,6 +136,14 @@ } } +clang_toolchain("clang_x64_v8_mips64") { + toolchain_args = { + current_cpu = "x64" + v8_current_cpu = "mips64" + current_os = "linux" + } +} + gcc_toolchain("x64") { cc = "gcc" cxx = "g++" @@ -202,3 +218,35 @@ is_clang = false } } + +gcc_toolchain("mips") { + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "mips" + current_os = "linux" + is_clang = false + } +} + +gcc_toolchain("mips64") { + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "mips64" + current_os = "linux" + is_clang = false + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java index 30ab1b09a..8481f12 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java
@@ -7,6 +7,8 @@ import android.Manifest; import android.annotation.TargetApi; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; @@ -53,10 +55,28 @@ static final String UNKNOWN_SSID = "<unknown ssid>"; static VisibleWifi getConnectedWifi(Context context, WifiManager wifiManager) { - if (!hasLocationAndWifiPermission(context)) { - return VisibleWifi.NO_WIFI_INFO; + if (hasLocationAndWifiPermission(context)) { + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + return connectedWifiInfoToVisibleWifi(wifiInfo); } - WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (hasLocationPermission(context)) { + // Only location permission, so fallback to pre-marshmallow. + return getConnectedWifiPreMarshmallow(context); + } + return VisibleWifi.NO_WIFI_INFO; + } + + static VisibleWifi getConnectedWifiPreMarshmallow(Context context) { + Intent intent = context.getApplicationContext().registerReceiver( + null, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION)); + if (intent != null) { + WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); + return connectedWifiInfoToVisibleWifi(wifiInfo); + } + return VisibleWifi.NO_WIFI_INFO; + } + + private static VisibleWifi connectedWifiInfoToVisibleWifi(@Nullable WifiInfo wifiInfo) { if (wifiInfo == null) { return VisibleWifi.NO_WIFI_INFO; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java index e6052d5..8942422 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
@@ -4,6 +4,10 @@ package org.chromium.chrome.browser; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; @@ -32,6 +36,8 @@ import org.chromium.ui.base.ActivityWindowAndroid; import org.chromium.ui.base.SelectFileDialog; +import java.util.Arrays; + /** * Integration test for select file dialog used for <input type="file" /> */ @@ -201,4 +207,24 @@ mActivityWindowAndroidForTest.lastCallback = null; mActivityWindowAndroidForTest.lastIntent = null; } + + @Test + @MediumTest + public void testPhotoPickerLaunchAndMimeTypes() throws Throwable { + assertEquals("", SelectFileDialog.ensureMimeType("")); + assertEquals("image/jpeg", SelectFileDialog.ensureMimeType(".jpg")); + assertEquals("image/jpeg", SelectFileDialog.ensureMimeType("image/jpeg")); + // Unknown extension, expect default response: + assertEquals("application/octet-stream", SelectFileDialog.ensureMimeType(".flv")); + + assertFalse(SelectFileDialog.usePhotoPicker(Arrays.asList(""))); + assertTrue(SelectFileDialog.usePhotoPicker(Arrays.asList(".jpg"))); + assertTrue(SelectFileDialog.usePhotoPicker(Arrays.asList("image/jpeg"))); + assertTrue(SelectFileDialog.usePhotoPicker(Arrays.asList(".jpg", "image/jpeg"))); + assertTrue(SelectFileDialog.usePhotoPicker(Arrays.asList(".gif", "image/jpeg"))); + // Returns false because generic picker is required (due to addition of .txt file). + assertFalse(SelectFileDialog.usePhotoPicker(Arrays.asList(".txt", ".jpg", "image/jpeg"))); + // Returns false because video file is included. + assertFalse(SelectFileDialog.usePhotoPicker(Arrays.asList(".jpg", "image/jpeg", ".mpg"))); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java index 2d668f7..1c750820 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java
@@ -7,12 +7,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -33,6 +37,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; @@ -140,6 +145,8 @@ private CellIdentityGsm mCellIdentityGsm; @Mock private CellIdentityCdma mCellIdentityCdma; + @Mock + private Intent mNetworkStateChangedIntent; @Before public void setUp() { @@ -220,6 +227,11 @@ .thenReturn( Arrays.asList(mCellInfoLte, mCellInfoWcdma, mCellInfoGsm, mCellInfoCdma)); allPermissionsGranted(); + + when(mContext.registerReceiver(eq(null), any(IntentFilter.class))) + .thenReturn(mNetworkStateChangedIntent); + when(mNetworkStateChangedIntent.getParcelableExtra(eq(WifiManager.EXTRA_WIFI_INFO))) + .thenReturn(mWifiInfo); } @Test @@ -368,11 +380,26 @@ @Test public void testGetConnectedWifi_locationGrantedWifiDenied() { - ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M); + ReflectionHelpers.setStaticField( + Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.LOLLIPOP); locationGrantedWifiDenied(); VisibleWifi visibleWifi = PlatformNetworksManager.getConnectedWifi(mContext, mWifiManager); + assertEquals(CONNECTED_WIFI, visibleWifi); + assertEquals(Long.valueOf(CURRENT_TIME_MS), visibleWifi.timestampMs()); + verifyNetworkStateAction(); + } + + @Test + public void testGetConnectedWifi_locationGrantedWifiDenied_noWifiInfo() { + ReflectionHelpers.setStaticField( + Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.LOLLIPOP); + locationGrantedWifiDenied(); + when(mNetworkStateChangedIntent.getParcelableExtra(eq(WifiManager.EXTRA_WIFI_INFO))) + .thenReturn(null); + VisibleWifi visibleWifi = PlatformNetworksManager.getConnectedWifi(mContext, mWifiManager); assertEquals(UNKNOWN_VISIBLE_WIFI, visibleWifi); assertNull(visibleWifi.timestampMs()); + verifyNetworkStateAction(); } @Test @@ -488,14 +515,15 @@ Set<VisibleCell> expectedVisibleCells = new HashSet<VisibleCell>(Arrays.asList(LTE_CELL, WCDMA_CELL, GSM_CELL, CDMA_CELL)); Set<VisibleWifi> expectedVisibleWifis = Collections.emptySet(); - VisibleNetworks expectedVisibleNetworks = - VisibleNetworks.create(null, LTE_CELL, expectedVisibleWifis, expectedVisibleCells); + VisibleNetworks expectedVisibleNetworks = VisibleNetworks.create( + CONNECTED_WIFI, LTE_CELL, expectedVisibleWifis, expectedVisibleCells); locationGrantedWifiDenied(); VisibleNetworks visibleNetworks = PlatformNetworksManager.computeVisibleNetworks( mContext, true /* includeAllVisibleNotConnectedNetworks */); assertEquals(expectedVisibleNetworks, visibleNetworks); + verifyNetworkStateAction(); } @Test @@ -547,4 +575,13 @@ any(Integer.class))) .thenReturn(wifiStatePermission); } + + private void verifyNetworkStateAction() { + verify(mContext).registerReceiver(eq(null), argThat(new ArgumentMatcher<IntentFilter>() { + @Override + public boolean matches(IntentFilter intentFilter) { + return intentFilter.hasAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + } + })); + } } \ No newline at end of file
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn index d0a83383..f09c501 100644 --- a/chrome/browser/android/vr_shell/BUILD.gn +++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -10,20 +10,16 @@ assert(enable_vr) if (current_cpu == "arm" || current_cpu == "arm64") { - static_library("vr_common") { - defines = [] - + # This library is platform-independent UI and related modules, which should + # compile on any platform. + static_library("vr_common_ui") { sources = [ - "android_ui_gesture_target.cc", - "android_ui_gesture_target.h", "animation.cc", "animation.h", "color_scheme.cc", "color_scheme.h", "easing.cc", "easing.h", - "elbow_model.cc", - "elbow_model.h", "font_fallback.cc", "font_fallback.h", "fps_meter.cc", @@ -32,10 +28,6 @@ "gltf_asset.h", "gltf_parser.cc", "gltf_parser.h", - "mailbox_to_surface_bridge.cc", - "mailbox_to_surface_bridge.h", - "non_presenting_gvr_delegate.cc", - "non_presenting_gvr_delegate.h", "textures/button_texture.cc", "textures/button_texture.h", "textures/close_button_texture.cc", @@ -88,6 +80,38 @@ "ui_scene_manager.h", "ui_unsupported_mode.h", "vr_browser_interface.h", + ] + + deps = [ + "//base", + "//cc/paint", + "//components/security_state/core", + "//components/url_formatter", + "//components/vector_icons", + "//content/public/browser", + "//content/public/common", + "//device/vr", + "//skia", + "//ui/base", + "//ui/display", + "//ui/gl", + "//ui/gl/init", + "//ui/vector_icons", + ] + } + + static_library("vr_common") { + defines = [] + + sources = [ + "android_ui_gesture_target.cc", + "android_ui_gesture_target.h", + "elbow_model.cc", + "elbow_model.h", + "mailbox_to_surface_bridge.cc", + "mailbox_to_surface_bridge.h", + "non_presenting_gvr_delegate.cc", + "non_presenting_gvr_delegate.h", "vr_compositor.cc", "vr_compositor.h", "vr_controller.cc", @@ -115,14 +139,12 @@ ] deps = [ + ":vr_common_ui", ":vr_shell_jni_headers", "//base", "//cc", "//chrome:resources", - "//components/omnibox/browser", "//components/rappor", - "//components/security_state/core", - "//components/vector_icons", "//content/public/android:jni", "//content/public/browser", "//content/public/common", @@ -134,7 +156,6 @@ "//ui/display", "//ui/gl", "//ui/gl/init", - "//ui/vector_icons", ] public_deps = [ @@ -172,21 +193,17 @@ ] deps = [ - ":vr_common", + ":vr_common_ui", "//base/test:run_all_unittests", "//base/test:test_support", - "//chrome/browser", - "//components/url_formatter", + "//components/security_state/core", + "//skia", "//testing/gmock", "//testing/gtest", - "//third_party/WebKit/public:blink", "//ui/gfx/geometry", + "//ui/gl", ] - # Ensure libgvr static library appears before gcc library in linking order. - # See https://crbug.com/704305 for details. - libs = [ "//third_party/gvr-android-sdk/libgvr_shim_static_${current_cpu}.a" ] - data = [ "test/data/sample_inline.gltf", "test/data/sample_external.gltf",
diff --git a/chrome/browser/android/vr_shell/ui_element_renderer.h b/chrome/browser/android/vr_shell/ui_element_renderer.h new file mode 100644 index 0000000..b14af75 --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_element_renderer.h
@@ -0,0 +1,31 @@ +// 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_ANDROID_VR_SHELL_UI_ELEMENT_RENDERER_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENT_RENDERER_H_ + +#include "device/vr/vr_types.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace vr_shell { + +// This is the interface offered by VrShell's GL system to UI elements. +class UiElementRenderer { + public: + virtual ~UiElementRenderer() {} + + virtual void DrawTexturedQuad(int texture_data_handle, + const vr::Mat4f& view_proj_matrix, + const gfx::RectF& copy_rect, + float opacity) = 0; + + virtual void DrawGradientQuad(const vr::Mat4f& view_proj_matrix, + const SkColor edge_color, + const SkColor center_color, + float opacity) = 0; +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENT_RENDERER_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc index 8e938c20..4ed2d7c7 100644 --- a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc +++ b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h" -#include "chrome/browser/android/vr_shell/vr_shell_renderer.h" +#include "chrome/browser/android/vr_shell/ui_element_renderer.h" #include "device/vr/vr_math.h" #include "third_party/skia/include/core/SkColor.h" @@ -24,13 +24,13 @@ set_fill(Fill::SELF); } -void ScreenDimmer::Render(VrShellRenderer* renderer, +void ScreenDimmer::Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const { vr::Mat4f m; vr::SetIdentityM(&m); vr::ScaleM(m, {2.0f, 2.0f, 1.0f}, &m); - renderer->GetGradientQuadRenderer()->Draw(m, kDimmerOuterColor, - kDimmerInnerColor, kDimmerOpacity); + renderer->DrawGradientQuad(m, kDimmerOuterColor, kDimmerInnerColor, + kDimmerOpacity); } } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h index c2e83f9..886e5199 100644 --- a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h +++ b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h
@@ -18,7 +18,7 @@ void Initialize() final; // UiElement interface. - void Render(VrShellRenderer* renderer, + void Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const final; DISALLOW_COPY_AND_ASSIGN(ScreenDimmer);
diff --git a/chrome/browser/android/vr_shell/ui_elements/textured_element.cc b/chrome/browser/android/vr_shell/ui_elements/textured_element.cc index c734358f..9593aa5 100644 --- a/chrome/browser/android/vr_shell/ui_elements/textured_element.cc +++ b/chrome/browser/android/vr_shell/ui_elements/textured_element.cc
@@ -7,7 +7,7 @@ #include "base/trace_event/trace_event.h" #include "cc/paint/skia_paint_canvas.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" -#include "chrome/browser/android/vr_shell/vr_shell_renderer.h" +#include "chrome/browser/android/vr_shell/ui_element_renderer.h" #include "third_party/skia/include/core/SkSurface.h" namespace vr_shell { @@ -39,15 +39,15 @@ Flush(surface.get()); } -void TexturedElement::Render(VrShellRenderer* renderer, +void TexturedElement::Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const { if (!initialized_) return; gfx::SizeF drawn_size = GetTexture()->GetDrawnSize(); gfx::RectF copy_rect(0, 0, drawn_size.width() / texture_size_.width(), drawn_size.height() / texture_size_.height()); - renderer->GetTexturedQuadRenderer()->AddQuad( - texture_handle_, view_proj_matrix, copy_rect, opacity()); + renderer->DrawTexturedQuad(texture_handle_, view_proj_matrix, copy_rect, + opacity()); } void TexturedElement::Flush(SkSurface* surface) {
diff --git a/chrome/browser/android/vr_shell/ui_elements/textured_element.h b/chrome/browser/android/vr_shell/ui_elements/textured_element.h index 59cb2b7..07b04e7 100644 --- a/chrome/browser/android/vr_shell/ui_elements/textured_element.h +++ b/chrome/browser/android/vr_shell/ui_elements/textured_element.h
@@ -26,7 +26,7 @@ void Initialize() final; // UiElement interface. - void Render(VrShellRenderer* renderer, + void Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const final; protected:
diff --git a/chrome/browser/android/vr_shell/ui_elements/ui_element.cc b/chrome/browser/android/vr_shell/ui_elements/ui_element.cc index 15fc6e26..10ce389 100644 --- a/chrome/browser/android/vr_shell/ui_elements/ui_element.cc +++ b/chrome/browser/android/vr_shell/ui_elements/ui_element.cc
@@ -109,7 +109,7 @@ UiElement::~UiElement() = default; -void UiElement::Render(VrShellRenderer* renderer, +void UiElement::Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const { NOTREACHED(); }
diff --git a/chrome/browser/android/vr_shell/ui_elements/ui_element.h b/chrome/browser/android/vr_shell/ui_elements/ui_element.h index 4ee49ae..1cdeac7 100644 --- a/chrome/browser/android/vr_shell/ui_elements/ui_element.h +++ b/chrome/browser/android/vr_shell/ui_elements/ui_element.h
@@ -22,7 +22,7 @@ namespace vr_shell { class Animation; -class VrShellRenderer; +class UiElementRenderer; enum XAnchoring { XNONE = 0, @@ -107,7 +107,7 @@ // Indicates whether the element should be tested for cursor input. bool IsHitTestable() const; - virtual void Render(VrShellRenderer* renderer, + virtual void Render(UiElementRenderer* renderer, vr::Mat4f view_proj_matrix) const; virtual void Initialize();
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index df63f33..f1173584 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/android/vr_shell/ui_elements/video_capture_indicator.h" #include "chrome/browser/android/vr_shell/ui_scene.h" #include "chrome/browser/android/vr_shell/vr_browser_interface.h" -#include "chrome/browser/android/vr_shell/vr_shell.h" namespace vr_shell {
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc index 1390d68..d5d3c86 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -817,6 +817,22 @@ VrShellRenderer::~VrShellRenderer() = default; +void VrShellRenderer::DrawTexturedQuad(int texture_data_handle, + const vr::Mat4f& view_proj_matrix, + const gfx::RectF& copy_rect, + float opacity) { + GetTexturedQuadRenderer()->AddQuad(texture_data_handle, view_proj_matrix, + copy_rect, opacity); +} + +void VrShellRenderer::DrawGradientQuad(const vr::Mat4f& view_proj_matrix, + const SkColor edge_color, + const SkColor center_color, + float opacity) { + GetGradientQuadRenderer()->Draw(view_proj_matrix, edge_color, center_color, + opacity); +} + ExternalTexturedQuadRenderer* VrShellRenderer::GetExternalTexturedQuadRenderer() { Flush();
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.h b/chrome/browser/android/vr_shell/vr_shell_renderer.h index 5759fea..6d8337a 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.h +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/macros.h" +#include "chrome/browser/android/vr_shell/ui_element_renderer.h" #include "chrome/browser/android/vr_shell/vr_controller_model.h" #include "device/vr/vr_types.h" #include "ui/gl/gl_bindings.h" @@ -272,11 +273,22 @@ DISALLOW_COPY_AND_ASSIGN(GradientGridRenderer); }; -class VrShellRenderer { +class VrShellRenderer : public UiElementRenderer { public: VrShellRenderer(); - ~VrShellRenderer(); + ~VrShellRenderer() override; + // UiElementRenderer interface (exposed to UI elements). + void DrawTexturedQuad(int texture_data_handle, + const vr::Mat4f& view_proj_matrix, + const gfx::RectF& copy_rect, + float opacity) override; + void DrawGradientQuad(const vr::Mat4f& view_proj_matrix, + const SkColor edge_color, + const SkColor center_color, + float opacity) override; + + // VrShell's internal GL rendering API. ExternalTexturedQuadRenderer* GetExternalTexturedQuadRenderer(); TexturedQuadRenderer* GetTexturedQuadRenderer(); WebVrRenderer* GetWebVrRenderer();
diff --git a/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc b/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc index 16eeece..8406b65 100644 --- a/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc
@@ -46,12 +46,12 @@ std::string apps_list; std::string expected_output; } kTestCases[] = { - { "", "none" }, - { "App1", "1 app (App1)" }, - { "App1, App2", "2 apps (App1, App2)" }, - { "App1, App2, App3", "3 apps (App1, App2, and 1 more)" }, - { "App1, App2, App3, App4", "4 apps (App1, App2, and 2 more)" }, - { "App1, App2, App3, App4, App5", "5 apps (App1, App2, and 3 more)" }, + {"", "None"}, + {"App1", "1 app (App1)"}, + {"App1, App2", "2 apps (App1, App2)"}, + {"App1, App2, App3", "3 apps (App1, App2, and 1 more)"}, + {"App1, App2, App3, App4", "4 apps (App1, App2, and 2 more)"}, + {"App1, App2, App3, App4, App5", "5 apps (App1, App2, and 3 more)"}, }; for (const TestCase& test_case : kTestCases) {
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc index 8b39df2f..3d8ea8bd 100644 --- a/chrome/browser/chrome_browser_field_trials.cc +++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -27,6 +27,7 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "components/metrics/metrics_pref_names.h" +#include "components/metrics/persistent_system_profile.h" #include "components/variations/variations_associated_data.h" #if defined(OS_ANDROID) @@ -156,6 +157,10 @@ if (!allocator) return; + // Store a copy of the system profile in this allocator. + metrics::GlobalPersistentSystemProfile::GetInstance() + ->RegisterPersistentAllocator(allocator->memory_allocator()); + // Create tracking histograms for the allocator and record storage file. allocator->CreateTrackingHistograms( ChromeMetricsServiceClient::kBrowserMetricsName);
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc index 569bc09..37cc99e 100644 --- a/chrome/browser/file_select_helper.cc +++ b/chrome/browser/file_select_helper.cc
@@ -354,6 +354,14 @@ } } +bool FileSelectHelper::AbortIfWebContentsDestroyed() { + if (render_frame_host_ && web_contents_) + return false; + + RunFileChooserEnd(); + return true; +} + std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> FileSelectHelper::GetFileTypesFromAcceptType( const std::vector<base::string16>& accept_types) { @@ -496,13 +504,18 @@ void FileSelectHelper::GetSanitizedFilenameOnUIThread( std::unique_ptr<FileChooserParams> params) { + if (AbortIfWebContentsDestroyed()) + return; + base::FilePath default_file_path = profile_->last_selected_directory().Append( GetSanitizedFileName(params->default_file_name)); #if defined(FULL_SAFE_BROWSING) - CheckDownloadRequestWithSafeBrowsing(default_file_path, std::move(params)); -#else - RunFileChooserOnUIThread(default_file_path, std::move(params)); + if (params->mode == FileChooserParams::Save) { + CheckDownloadRequestWithSafeBrowsing(default_file_path, std::move(params)); + return; + } #endif + RunFileChooserOnUIThread(default_file_path, std::move(params)); } #if defined(FULL_SAFE_BROWSING) @@ -557,13 +570,8 @@ const base::FilePath& default_file_path, std::unique_ptr<FileChooserParams> params) { DCHECK(params); - if (!render_frame_host_ || !web_contents_ || !IsValidProfile(profile_) || - !web_contents_->GetNativeView()) { - // If the renderer was destroyed before we started, just cancel the - // operation. - RunFileChooserEnd(); + if (AbortIfWebContentsDestroyed()) return; - } select_file_dialog_ = ui::SelectFileDialog::Create( this, new ChromeSelectFilePolicy(web_contents_)); @@ -615,9 +623,9 @@ select_file_types_.reset(); } -// This method is called when we receive the last callback from the file -// chooser dialog. Perform any cleanup and release the reference we added -// in RunFileChooser(). +// This method is called when we receive the last callback from the file chooser +// dialog or if the renderer was destroyed. Perform any cleanup and release the +// reference we added in RunFileChooser(). void FileSelectHelper::RunFileChooserEnd() { // If there are temporary files, then this instance needs to stick around // until web_contents_ is destroyed, so that this instance can delete the
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h index 06e1b9d..7d1c694 100644 --- a/chrome/browser/file_select_helper.h +++ b/chrome/browser/file_select_helper.h
@@ -191,6 +191,10 @@ // Cleans up when the initiator of the file chooser is no longer valid. void CleanUp(); + // Calls RunFileChooserEnd() if the webcontents was destroyed. Returns true + // if the file chooser operation shouldn't proceed. + bool AbortIfWebContentsDestroyed(); + // Helper method to get allowed extensions for select file dialog from // the specified accept types as defined in the spec: // http://whatwg.org/html/number-state.html#attr-input-accept
diff --git a/chrome/browser/ssl/common_name_mismatch_handler.cc b/chrome/browser/ssl/common_name_mismatch_handler.cc index 9a7c9f3e..38ad835 100644 --- a/chrome/browser/ssl/common_name_mismatch_handler.cc +++ b/chrome/browser/ssl/common_name_mismatch_handler.cc
@@ -19,7 +19,9 @@ const scoped_refptr<net::URLRequestContextGetter>& request_context) : request_url_(request_url), request_context_(request_context) {} -CommonNameMismatchHandler::~CommonNameMismatchHandler() {} +CommonNameMismatchHandler::~CommonNameMismatchHandler() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} // static CommonNameMismatchHandler::TestingState @@ -32,7 +34,7 @@ if (testing_state_ == IGNORE_REQUESTS_FOR_TESTING) return; - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsCheckingSuggestedUrl()); DCHECK(check_url_callback_.is_null()); @@ -105,7 +107,7 @@ void CommonNameMismatchHandler::OnURLFetchComplete( const net::URLFetcher* source) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(IsCheckingSuggestedUrl()); DCHECK_EQ(url_fetcher_.get(), source); DCHECK(!check_url_callback_.is_null());
diff --git a/chrome/browser/ssl/common_name_mismatch_handler.h b/chrome/browser/ssl/common_name_mismatch_handler.h index 5d36226..d79f57ee 100644 --- a/chrome/browser/ssl/common_name_mismatch_handler.h +++ b/chrome/browser/ssl/common_name_mismatch_handler.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "base/time/time.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" @@ -24,8 +24,7 @@ // This class handles errors due to common name mismatches // (|ERR_CERT_COMMON_NAME_INVALID|) and helps remediate them by suggesting // alternative URLs that may be what the user intended to load. -class CommonNameMismatchHandler : public net::URLFetcherDelegate, - public base::NonThreadSafe { +class CommonNameMismatchHandler : public net::URLFetcherDelegate { public: enum SuggestedUrlCheckResult { // The request succeeds with good response code i.e. URL exists and its @@ -86,6 +85,8 @@ CheckUrlCallback check_url_callback_; std::unique_ptr<net::URLFetcher> url_fetcher_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(CommonNameMismatchHandler); };
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc index 2bbdd3e..a446078 100644 --- a/chrome/browser/ssl/ssl_error_handler.cc +++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -16,7 +16,6 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" -#include "base/threading/non_thread_safe.h" #include "base/time/clock.h" #include "base/time/time.h" #include "chrome/browser/browser_process.h" @@ -168,7 +167,7 @@ } // Configuration for SSLErrorHandler. -class ConfigSingleton : public base::NonThreadSafe { +class ConfigSingleton { public: ConfigSingleton();
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 3a0161e9..6a9d0e1 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -225,11 +225,12 @@ weak_ptr_factory_(this) {} ThemeService::~ThemeService() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); FreePlatformCaches(); } void ThemeService::Init(Profile* profile) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); profile_ = profile; LoadThemePrefs(); @@ -520,7 +521,7 @@ } color_utils::HSL ThemeService::GetTint(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); color_utils::HSL hsl; if (theme_supplier_ && theme_supplier_->GetTint(id, &hsl)) @@ -694,7 +695,7 @@ } SkColor ThemeService::GetColor(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // For legacy reasons, |theme_supplier_| requires the incognito variants // of color IDs. @@ -758,7 +759,7 @@ } gfx::Image ThemeService::GetImageNamed(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); int adjusted_id = id; if (incognito) {
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h index 843fa91..51c676c 100644 --- a/chrome/browser/themes/theme_service.h +++ b/chrome/browser/themes/theme_service.h
@@ -15,7 +15,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "build/build_config.h" #include "chrome/common/features.h" #include "components/keyed_service/core/keyed_service.h" @@ -59,9 +59,7 @@ extern "C" NSString* const kBrowserThemeDidChangeNotification; #endif // __OBJC__ -class ThemeService : public base::NonThreadSafe, - public content::NotificationObserver, - public KeyedService { +class ThemeService : public content::NotificationObserver, public KeyedService { public: // Public constants used in ThemeService and its subclasses: static const char kDefaultThemeID[]; @@ -328,6 +326,8 @@ BrowserThemeProvider original_theme_provider_; BrowserThemeProvider incognito_theme_provider_; + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<ThemeService> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ThemeService);
diff --git a/chrome/browser/themes/theme_service_mac.mm b/chrome/browser/themes/theme_service_mac.mm index 4ede577..e77cfcf 100644 --- a/chrome/browser/themes/theme_service_mac.mm +++ b/chrome/browser/themes/theme_service_mac.mm
@@ -44,7 +44,7 @@ } // namespace NSImage* ThemeService::GetNSImageNamed(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); bool is_tab_or_toolbar_color = id == IDR_THEME_TAB_BACKGROUND_INACTIVE || @@ -147,7 +147,7 @@ } NSColor* ThemeService::GetNSImageColorNamed(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); bool is_tab_or_toolbar_color = id == IDR_THEME_TAB_BACKGROUND_INACTIVE || @@ -187,7 +187,7 @@ } NSColor* ThemeService::GetNSColor(int id, bool incognito) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); int original_id = id; const bool is_mode_material = true; @@ -216,7 +216,7 @@ } NSColor* ThemeService::GetNSColorTint(int id) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Check to see if we already have the color in the cache. NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id); @@ -245,7 +245,7 @@ } NSGradient* ThemeService::GetNSGradient(int id) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Check to see if we already have the gradient in the cache. NSGradientMap::const_iterator nsgradient_iter = nsgradient_cache_.find(id); @@ -328,7 +328,7 @@ } void ThemeService::FreePlatformCaches() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Free images. for (NSImageMap::iterator i = nsimage_cache_.begin();
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc index 34325a2..1802b08 100644 --- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc +++ b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
@@ -136,6 +136,17 @@ return false; } +std::unique_ptr<net::test_server::HttpResponse> EmptyHtmlResponseHandler( + const net::test_server::HttpRequest& request) { + std::unique_ptr<net::test_server::BasicHttpResponse> http_response( + new net::test_server::BasicHttpResponse()); + http_response->set_code(net::HTTP_OK); + http_response->set_content_type("text/html"); + http_response->set_content( + "<html><head><link rel=manifest href=/manifest.json></head></html>"); + return std::move(http_response); +} + // This class is used to mock out virtual methods with side effects so that // tests below can ensure they are called without causing side effects. class MockInlineSigninHelper : public InlineSigninHelper { @@ -809,6 +820,9 @@ private: void SetUp() override { + embedded_test_server()->RegisterRequestHandler( + base::Bind(&EmptyHtmlResponseHandler)); + // Don't spin up the IO thread yet since no threads are allowed while // spawning sandbox host process. See crbug.com/322732. ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); @@ -869,7 +883,7 @@ // http://crbug.com/709117. // Flaky on Linux and Mac. http://crbug.com/722164. IN_PROC_BROWSER_TEST_F(InlineLoginUISafeIframeBrowserTest, - DISABLED_LoadSuccessContinueURL) { + LoadSuccessContinueURL) { ui_test_utils::NavigateToURL(browser(), GetSigninPromoURL()); WaitUntilUIReady(browser()); @@ -888,13 +902,12 @@ kLoadSuccessPageScript, success_url.c_str(), success_url.c_str()); std::string message; - ASSERT_TRUE(content::ExecuteScriptAndExtractString( + EXPECT_TRUE(content::ExecuteScriptAndExtractString( browser()->tab_strip_model()->GetActiveWebContents(), script, &message)); EXPECT_EQ("success_page_loaded", message); } // Make sure that the gaia iframe cannot trigger top-frame navigation. -// TODO(guohui): flaky on trybot crbug/364759. IN_PROC_BROWSER_TEST_F(InlineLoginUISafeIframeBrowserTest, TopFrameNavigationDisallowed) { // Loads into gaia iframe a web page that attempts to deframe on load.
diff --git a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc index 897e15b..3d7d234 100644 --- a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc +++ b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
@@ -453,4 +453,27 @@ RunTestViaHTTP("FileChooser_SaveAsDangerousExtensionListDisallowed"); } +IN_PROC_BROWSER_TEST_F(PPAPIFileChooserTestWithSBService, + FileChooser_Open_NotBlockedBySafeBrowsing) { + base::ThreadRestrictions::ScopedAllowIO allow_io; + const char kContents[] = "Hello from browser"; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + base::FilePath existing_filename = temp_dir.GetPath().AppendASCII("foo"); + ASSERT_EQ( + static_cast<int>(sizeof(kContents) - 1), + base::WriteFile(existing_filename, kContents, sizeof(kContents) - 1)); + + safe_browsing_test_configuration_.default_result = + DownloadProtectionService::DANGEROUS; + + TestSelectFileDialogFactory::SelectedFileInfoList file_info_list; + file_info_list.push_back( + ui::SelectedFileInfo(existing_filename, existing_filename)); + TestSelectFileDialogFactory test_dialog_factory( + TestSelectFileDialogFactory::RESPOND_WITH_FILE_LIST, file_info_list); + RunTestViaHTTP("FileChooser_OpenSimple"); +} + #endif // FULL_SAFE_BROWSING
diff --git a/components/browsing_data/core/browsing_data_utils.h b/components/browsing_data/core/browsing_data_utils.h index 133e744..3e087f8 100644 --- a/components/browsing_data/core/browsing_data_utils.h +++ b/components/browsing_data/core/browsing_data_utils.h
@@ -52,8 +52,8 @@ void RecordDeletionForPeriod(TimePeriod time_period); // Constructs the text to be displayed by a counter from the given |result|. -// Currently this can only be used for counters for which the Result is defined -// in components/browsing_data/core/counters. +// Currently this can only be used for counters for which the Result is +// defined in components/browsing_data/core/counters. base::string16 GetCounterTextFromResult( const BrowsingDataCounter::Result* result);
diff --git a/components/browsing_data/core/browsing_data_utils_unittest.cc b/components/browsing_data/core/browsing_data_utils_unittest.cc index a39dbbd7..12a870e 100644 --- a/components/browsing_data/core/browsing_data_utils_unittest.cc +++ b/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -63,8 +63,8 @@ bool sync_enabled; std::string expected_output; } kTestCases[] = { - {0, 0, 0, false, "none"}, - {0, 0, 0, true, "none"}, + {0, 0, 0, false, "None"}, + {0, 0, 0, true, "None"}, {1, 0, 0, false, "1 credit card"}, {0, 5, 0, false, "5 addresses"}, {0, 0, 1, false, "1 suggestion"}, @@ -107,7 +107,7 @@ int is_synced; std::string expected_output; } kTestCases[] = { - {0, false, "none"}, {0, true, "none"}, + {0, false, "None"}, {0, true, "None"}, {1, false, "1 password"}, {1, true, "1 password (synced)"}, {5, false, "5 passwords"}, {5, true, "5 passwords (synced)"}, };
diff --git a/components/browsing_data_strings.grdp b/components/browsing_data_strings.grdp index 67110ee..a2a61af 100644 --- a/components/browsing_data_strings.grdp +++ b/components/browsing_data_strings.grdp
@@ -6,45 +6,45 @@ </message> <message name="IDS_DEL_BROWSING_HISTORY_COUNTER" desc="A counter showing how many items of browsing history the user has."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 item} other {# items}} </message> <message name="IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED" desc="A counter showing the user how many local items of browsing history they have, and informing them that more items might be synced. In the case when COUNT is zero, the counter only mentions existence of synced items."> {COUNT, plural, - =0 {at least 1 item on synced devices} + =0 {At least 1 item on synced devices} =1 {1 item (and more on synced devices)} other {# items (and more on synced devices)}} </message> <message name="IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE" desc="A counter showing that the user has less than X megabytes of cache. The value X will be substituted."> - less than <ph name="UPPER_ESTIMATE">$1<ex>328 MB</ex></ph> + Less than <ph name="UPPER_ESTIMATE">$1<ex>328 MB</ex></ph> </message> <message name="IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY" desc="A counter showing that the user's cache is almost empty, having less than 1 MB of data."> - less than 1 MB + Less than 1 MB </message> <message name="IDS_DEL_CACHE_COUNTER_BASIC" desc="A counter showing the size of the users's cache including either 'x MB' or 'less than x MB' as $1 and explaining that the cache is used to speed up the loading of websites."> Frees up <ph name="SIZE">$1<ex>328 MB</ex></ph>. Some sites may load more slowly on your next visit. </message> <message name="IDS_DEL_PASSWORDS_COUNTER" desc="A counter showing how many passwords the user has."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 password} other {# passwords}} </message> <message name="IDS_DEL_PASSWORDS_COUNTER_SYNCED" desc="A counter showing how many passwords the user has and that they are synced."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 password (synced)} other {# passwords (synced)}} </message> <message name="IDS_DEL_SITE_SETTINGS_COUNTER" desc="A counter showing how many sites with site settings the user has."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 site} other {# sites}} </message> <message name="IDS_DEL_AUTOFILL_COUNTER_EMPTY" desc="A counter showing that the user has no form data stored."> - none + None </message> <message name="IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS" desc="A counter showing how many credit cards the user has."> {COUNT, plural, @@ -91,19 +91,19 @@ </message> <message name="IDS_DEL_COOKIES_COUNTER_ADVANCED" desc="A counter showing the number of sites that use cookies."> {COUNT, plural, - =0 {No cookies} - =1 {1 site uses cookies. } - other {# sites use cookies. }} + =0 {None} + =1 {From 1 site } + other {From # sites }} </message> <message name="IDS_DEL_DOWNLOADS_COUNTER" desc="A counter showing how many items of downloads history the user has."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 item} other {# items}} </message> <message name="IDS_DEL_HOSTED_APPS_COUNTER" desc="A counter showing how many hosted apps the user has. We show the number of apps, and in the cases where there is one or two apps, we will also give two example app names, denoted as placeholders $1 and $2. If there are more than two apps, we will give two examples and say 'and X more'. The 'and X more' string, denoted by the placeholder $3, will be supplied from another message."> {COUNT, plural, - =0 {none} + =0 {None} =1 {1 app ($1)} =2 {2 apps ($1, $2)} other {# apps ($1, $2, $3)}}
diff --git a/components/keyed_service/content/browser_context_keyed_base_factory.cc b/components/keyed_service/content/browser_context_keyed_base_factory.cc index 7c2d8b79..4c8aba3b 100644 --- a/components/keyed_service/content/browser_context_keyed_base_factory.cc +++ b/components/keyed_service/content/browser_context_keyed_base_factory.cc
@@ -19,7 +19,7 @@ content::BrowserContext* BrowserContextKeyedBaseFactory::GetBrowserContextToUse( content::BrowserContext* context) const { // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse(). - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Safe default for the Incognito mode: no service. if (context->IsOffTheRecord())
diff --git a/components/keyed_service/content/browser_context_keyed_service_factory.cc b/components/keyed_service/content/browser_context_keyed_service_factory.cc index 38f6ca61..6cc7d94 100644 --- a/components/keyed_service/content/browser_context_keyed_service_factory.cc +++ b/components/keyed_service/content/browser_context_keyed_service_factory.cc
@@ -49,7 +49,7 @@ BrowserContextKeyedServiceFactory::GetBrowserContextToUse( content::BrowserContext* context) const { // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse(). - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Safe default for Incognito mode: no service. if (context->IsOffTheRecord())
diff --git a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc index 7778de8..df8908a 100644 --- a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc +++ b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
@@ -50,7 +50,7 @@ RefcountedBrowserContextKeyedServiceFactory::GetBrowserContextToUse( content::BrowserContext* context) const { // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse(). - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Safe default for Incognito mode: no service. if (context->IsOffTheRecord())
diff --git a/components/keyed_service/core/keyed_service_base_factory.cc b/components/keyed_service/core/keyed_service_base_factory.cc index 48643305..773b1f9 100644 --- a/components/keyed_service/core/keyed_service_base_factory.cc +++ b/components/keyed_service/core/keyed_service_base_factory.cc
@@ -53,6 +53,7 @@ } KeyedServiceBaseFactory::~KeyedServiceBaseFactory() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); dependency_manager_->RemoveComponent(this); } @@ -88,7 +89,7 @@ } void KeyedServiceBaseFactory::MarkContextLive(base::SupportsUserData* context) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); dependency_manager_->MarkContextLive(context); } @@ -104,7 +105,7 @@ base::SupportsUserData* context) { // While object destruction can be customized in ways where the object is // only dereferenced, this still must run on the UI thread. - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); registered_preferences_.erase(context); }
diff --git a/components/keyed_service/core/keyed_service_base_factory.h b/components/keyed_service/core/keyed_service_base_factory.h index ea9223b..94d01d7 100644 --- a/components/keyed_service/core/keyed_service_base_factory.h +++ b/components/keyed_service/core/keyed_service_base_factory.h
@@ -7,7 +7,7 @@ #include <set> -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "components/keyed_service/core/dependency_node.h" #include "components/keyed_service/core/keyed_service_export.h" @@ -29,8 +29,7 @@ // This object describes general dependency management between factories while // direct subclasses react to lifecycle events and implement memory management. class KEYED_SERVICE_EXPORT KeyedServiceBaseFactory - : public base::NonThreadSafe, - NON_EXPORTED_BASE(public DependencyNode) { + : NON_EXPORTED_BASE(public DependencyNode) { public: #ifndef NDEBUG // Returns our name. We don't keep track of this in release mode. @@ -112,6 +111,8 @@ // Mark context has having preferences registered. void MarkPreferencesSetOn(base::SupportsUserData* context); + SEQUENCE_CHECKER(sequence_checker_); + private: friend class DependencyManager;
diff --git a/components/keyed_service/ios/browser_state_keyed_service_factory.cc b/components/keyed_service/ios/browser_state_keyed_service_factory.cc index 105e6992..d953120 100644 --- a/components/keyed_service/ios/browser_state_keyed_service_factory.cc +++ b/components/keyed_service/ios/browser_state_keyed_service_factory.cc
@@ -43,7 +43,7 @@ web::BrowserState* BrowserStateKeyedServiceFactory::GetBrowserStateToUse( web::BrowserState* context) const { // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse(). - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Safe default for Incognito mode: no service. if (context->IsOffTheRecord())
diff --git a/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc b/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc index a9abd88..98a3cae8 100644 --- a/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc +++ b/components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc
@@ -50,7 +50,7 @@ RefcountedBrowserStateKeyedServiceFactory::GetBrowserStateToUse( web::BrowserState* context) const { // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse(). - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Safe default for Incognito mode: no service. if (context->IsOffTheRecord())
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index 1d03801..8cb72a3 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -77,6 +77,8 @@ "persisted_logs_metrics.h", "persisted_logs_metrics_impl.cc", "persisted_logs_metrics_impl.h", + "persistent_system_profile.cc", + "persistent_system_profile.h", "reporting_service.cc", "reporting_service.h", "stability_metrics_helper.cc", @@ -352,6 +354,7 @@ "net/net_metrics_log_uploader_unittest.cc", "net/network_metrics_provider_unittest.cc", "persisted_logs_unittest.cc", + "persistent_system_profile_unittest.cc", "profiler/profiler_metrics_provider_unittest.cc", "profiler/tracking_synchronizer_unittest.cc", "single_sample_metrics_factory_impl_unittest.cc",
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index ac35ce3..0d9367b 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -22,6 +22,7 @@ #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_provider.h" #include "components/metrics/metrics_service_client.h" +#include "components/metrics/persistent_system_profile.h" #include "components/metrics/proto/histogram_event.pb.h" #include "components/metrics/proto/system_profile.pb.h" #include "components/metrics/proto/user_action_event.pb.h" @@ -303,7 +304,13 @@ metrics_providers[i]->ProvideSystemProfileMetrics(system_profile); EnvironmentRecorder recorder(local_state_); - return recorder.SerializeAndRecordEnvironmentToPrefs(*system_profile); + std::string serialized_proto = + recorder.SerializeAndRecordEnvironmentToPrefs(*system_profile); + + GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile( + serialized_proto); + + return serialized_proto; } bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
diff --git a/components/metrics/persistent_system_profile.cc b/components/metrics/persistent_system_profile.cc new file mode 100644 index 0000000..526b1407 --- /dev/null +++ b/components/metrics/persistent_system_profile.cc
@@ -0,0 +1,301 @@ +// 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/metrics/persistent_system_profile.h" + +#include "base/atomicops.h" +#include "base/memory/singleton.h" +#include "base/metrics/persistent_memory_allocator.h" +#include "base/stl_util.h" + +namespace metrics { + +namespace { + +// To provide atomic addition of records so that there is no confusion between +// writers and readers, all of the metadata about a record is contained in a +// structure that can be stored as a single atomic 32-bit word. +union RecordHeader { + struct { + unsigned continued : 1; // Flag indicating if there is more after this. + unsigned type : 7; // The type of this record. + unsigned amount : 24; // The amount of data to follow. + } as_parts; + base::subtle::Atomic32 as_atomic; +}; + +constexpr uint32_t kTypeIdSystemProfile = 0x330A7150; // SHA1(SystemProfile) +constexpr size_t kSystemProfileAllocSize = 4 << 10; // 4 KiB +constexpr size_t kMaxRecordSize = (1 << 24) - sizeof(RecordHeader); + +static_assert(sizeof(RecordHeader) == sizeof(base::subtle::Atomic32), + "bad RecordHeader size"); + +// Calculate the size of a record based on the amount of data. This adds room +// for the record header and rounds up to the next multiple of the record-header +// size. +size_t CalculateRecordSize(size_t data_amount) { + return (data_amount + sizeof(RecordHeader) + sizeof(RecordHeader) - 1) & + ~(sizeof(RecordHeader) - 1); +} + +} // namespace + +PersistentSystemProfile::RecordAllocator::RecordAllocator( + base::PersistentMemoryAllocator* memory_allocator, + size_t min_size) + : allocator_(memory_allocator), + alloc_reference_(0), + alloc_size_(0), + end_offset_(0) { + AddSegment(min_size); +} + +PersistentSystemProfile::RecordAllocator::RecordAllocator( + const base::PersistentMemoryAllocator* memory_allocator) + : allocator_( + const_cast<base::PersistentMemoryAllocator*>(memory_allocator)), + alloc_reference_(0), + alloc_size_(0), + end_offset_(0) {} + +void PersistentSystemProfile::RecordAllocator::Reset() { + // Clear the first word of all blocks so they're known to be "empty". + alloc_reference_ = 0; + while (NextSegment()) { + // Get the block as a char* and cast it. It can't be fetched directly as + // an array of RecordHeader because that's not a fundamental type and only + // arrays of fundamental types are allowed. + RecordHeader* header = + reinterpret_cast<RecordHeader*>(allocator_->GetAsArray<char>( + alloc_reference_, kTypeIdSystemProfile, sizeof(RecordHeader))); + DCHECK(header); + base::subtle::NoBarrier_Store(&header->as_atomic, 0); + } + + // Reset member variables. + alloc_reference_ = 0; + alloc_size_ = 0; + end_offset_ = 0; +} + +bool PersistentSystemProfile::RecordAllocator::Write( + RecordType type, + const std::string& record) { + const char* data = record.data(); + size_t remaining_size = record.size(); + + // Allocate space and write records until everything has been stored. + do { + if (end_offset_ == alloc_size_) { + if (!AddSegment(remaining_size)) + return false; + } + // Write out as much of the data as possible. |data| and |remaining_size| + // are updated in place. + if (!WriteData(type, &data, &remaining_size)) + return false; + } while (remaining_size > 0); + + return true; +} + +bool PersistentSystemProfile::RecordAllocator::Read(RecordType* type, + std::string* record) const { + *type = kUnusedSpace; + record->clear(); + + // Access data and read records until everything has been loaded. + while (true) { + if (end_offset_ == alloc_size_) { + if (!NextSegment()) + return false; + } + if (ReadData(type, record)) + return *type != kUnusedSpace; + } +} + +bool PersistentSystemProfile::RecordAllocator::NextSegment() const { + base::PersistentMemoryAllocator::Iterator iter(allocator_, alloc_reference_); + alloc_reference_ = iter.GetNextOfType(kTypeIdSystemProfile); + alloc_size_ = allocator_->GetAllocSize(alloc_reference_); + end_offset_ = 0; + return alloc_reference_ != 0; +} + +bool PersistentSystemProfile::RecordAllocator::AddSegment(size_t min_size) { + if (NextSegment()) { + // The first record-header should have been zeroed as part of the allocation + // or by the "reset" procedure. + DCHECK_EQ(0, base::subtle::NoBarrier_Load( + allocator_->GetAsArray<base::subtle::Atomic32>( + alloc_reference_, kTypeIdSystemProfile, 1))); + return true; + } + + DCHECK_EQ(0U, alloc_reference_); + DCHECK_EQ(0U, end_offset_); + + size_t size = + std::max(CalculateRecordSize(min_size), kSystemProfileAllocSize); + + uint32_t ref = allocator_->Allocate(size, kTypeIdSystemProfile); + if (!ref) + return false; // Allocator must be full. + allocator_->MakeIterable(ref); + + alloc_reference_ = ref; + alloc_size_ = allocator_->GetAllocSize(ref); + return true; +} + +bool PersistentSystemProfile::RecordAllocator::WriteData( + RecordType type, + const char** data, + size_t* remaining_size) { + char* block = + allocator_->GetAsArray<char>(alloc_reference_, kTypeIdSystemProfile, + base::PersistentMemoryAllocator::kSizeAny); + if (!block) + return false; // It's bad if there is no accessible block. + + size_t write_size = std::min(*remaining_size, kMaxRecordSize); + write_size = + std::min(write_size, alloc_size_ - end_offset_ - sizeof(RecordHeader)); + + // Write the data and the record header. + RecordHeader header; + header.as_atomic = 0; + header.as_parts.type = type; + header.as_parts.amount = write_size; + header.as_parts.continued = (write_size < *remaining_size); + size_t offset = end_offset_; + end_offset_ += CalculateRecordSize(write_size); + DCHECK_GE(alloc_size_, end_offset_); + if (end_offset_ < alloc_size_) { + // An empty record header has to be next before this one gets written. + base::subtle::NoBarrier_Store( + reinterpret_cast<base::subtle::Atomic32*>(block + end_offset_), 0); + } + memcpy(block + offset + sizeof(header), *data, write_size); + base::subtle::Release_Store(reinterpret_cast<base::subtle::Atomic32*>(block), + header.as_atomic); + + // Account for what was stored and prepare for follow-on records with any + // remaining data. + *data += write_size; + *remaining_size -= write_size; + + return true; +} + +bool PersistentSystemProfile::RecordAllocator::ReadData( + RecordType* type, + std::string* record) const { + DCHECK_GT(alloc_size_, end_offset_); + + char* block = + allocator_->GetAsArray<char>(alloc_reference_, kTypeIdSystemProfile, + base::PersistentMemoryAllocator::kSizeAny); + if (!block) { + *type = kUnusedSpace; + return true; // No more data. + } + + // Get and validate the record header. + RecordHeader header; + header.as_atomic = base::subtle::Acquire_Load( + reinterpret_cast<base::subtle::Atomic32*>(block + end_offset_)); + bool continued = !!header.as_parts.continued; + if (header.as_parts.type == kUnusedSpace) { + *type = kUnusedSpace; + return true; // End of all records. + } else if (*type == kUnusedSpace) { + *type = static_cast<RecordType>(header.as_parts.type); + } else if (*type != header.as_parts.type) { + NOTREACHED(); // Continuation didn't match start of record. + *type = kUnusedSpace; + record->clear(); + return false; + } + size_t read_size = header.as_parts.amount; + if (read_size < sizeof(header) || + end_offset_ + sizeof(header) + read_size > alloc_size_) { + NOTREACHED(); // Invalid header amount. + *type = kUnusedSpace; + return true; // Don't try again. + } + + // Append the record data to the output string. + record->append(block + sizeof(header), read_size); + end_offset_ += CalculateRecordSize(read_size); + DCHECK_GE(alloc_size_, end_offset_); + + return !continued; +} + +PersistentSystemProfile::PersistentSystemProfile() {} + +PersistentSystemProfile::~PersistentSystemProfile() {} + +void PersistentSystemProfile::RegisterPersistentAllocator( + base::PersistentMemoryAllocator* memory_allocator) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // Create and store the allocator. A |min_size| of "1" ensures that a memory + // block is reserved now. + RecordAllocator allocator(memory_allocator, 1); + allocators_.push_back(std::move(allocator)); +} + +void PersistentSystemProfile::DeregisterPersistentAllocator( + base::PersistentMemoryAllocator* memory_allocator) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // This would be more efficient with a std::map but it's not expected that + // allocators will get deregistered with any frequency, if at all. + base::EraseIf(allocators_, [=](RecordAllocator& records) { + return records.allocator() == memory_allocator; + }); +} + +void PersistentSystemProfile::SetSystemProfile( + const std::string& serialized_profile) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (allocators_.empty() || serialized_profile.empty()) + return; + + for (auto& allocator : allocators_) { + // A full system profile always starts fresh. + allocator.Reset(); + // Write out the serialized profile. + allocator.Write(kSystemProfileProto, serialized_profile); + } +} + +// static +bool PersistentSystemProfile::GetSystemProfile( + const base::PersistentMemoryAllocator& memory_allocator, + SystemProfileProto* system_profile) { + const RecordAllocator records(&memory_allocator); + + RecordType type; + std::string record; + if (!records.Read(&type, &record)) + return false; + if (type != kSystemProfileProto) + return false; + + return system_profile->ParseFromString(record); +} + +GlobalPersistentSystemProfile* GlobalPersistentSystemProfile::GetInstance() { + return base::Singleton< + GlobalPersistentSystemProfile, + base::LeakySingletonTraits<GlobalPersistentSystemProfile>>::get(); +} + +} // namespace metrics
diff --git a/components/metrics/persistent_system_profile.h b/components/metrics/persistent_system_profile.h new file mode 100644 index 0000000..30d971f6 --- /dev/null +++ b/components/metrics/persistent_system_profile.h
@@ -0,0 +1,126 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_ +#define BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_ + +#include <vector> + +#include "base/threading/thread_checker.h" +#include "components/metrics/proto/system_profile.pb.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +class PersistentMemoryAllocator; +} // namespace base + +namespace metrics { + +// Manages a copy of the system profile inside persistent memory segments. +class PersistentSystemProfile { + public: + PersistentSystemProfile(); + ~PersistentSystemProfile(); + + // This object can store records in multiple memory allocators. + void RegisterPersistentAllocator( + base::PersistentMemoryAllocator* memory_allocator); + void DeregisterPersistentAllocator( + base::PersistentMemoryAllocator* memory_allocator); + + // Stores a complete system profile. + void SetSystemProfile(const std::string& serialized_profile); + + // Retrieves the system profile from a persistent memory allocator. Returns + // true if a profile was successfully retrieved. + static bool GetSystemProfile( + const base::PersistentMemoryAllocator& memory_allocator, + SystemProfileProto* system_profile); + + private: + friend class PersistentSystemProfileTest; + + // Defines record types that can be stored inside our local Allocators. + enum RecordType : uint8_t { + kUnusedSpace = 0, // The default value for empty memory. + kSystemProfileProto, + }; + + // A class for managing record allocations inside a persistent memory segment. + class RecordAllocator { + public: + // Construct an allocator for writing. + RecordAllocator(base::PersistentMemoryAllocator* memory_allocator, + size_t min_size); + + // Construct an allocator for reading. + RecordAllocator(const base::PersistentMemoryAllocator* memory_allocator); + + // These methods manage writing records to the allocator. Do not mix these + // with "read" calls; it's one or the other. + void Reset(); + bool Write(RecordType type, const std::string& record); + + // Read a record from the allocator. Do not mix this with "write" calls; + // it's one or the other. + bool Read(RecordType* type, std::string* record) const; + + base::PersistentMemoryAllocator* allocator() { return allocator_; } + + private: + // Advance to the next record segment in the memory allocator. + bool NextSegment() const; + + // Advance to the next record segment, creating a new one if necessary with + // sufficent |min_size| space. + bool AddSegment(size_t min_size); + + // Writes data to the current position, updating the passed values past + // the amount written. Returns false in case of an error. + bool WriteData(RecordType type, const char** data, size_t* remaining_size); + + // Reads data from the current position, updating the passed string + // in-place. |type| must be initialized to kUnusedSpace and |record| must + // be an empty string before the first call but unchanged thereafter. + // Returns true when record is complete. + bool ReadData(RecordType* type, std::string* record) const; + + // This never changes but can't be "const" because vector calls operator=(). + base::PersistentMemoryAllocator* allocator_; // Storage location. + + // These change even though the underlying data may be "const". + mutable uint32_t alloc_reference_; // Last storage block. + mutable size_t alloc_size_; // Size of the block. + mutable size_t end_offset_; // End of data in block. + + // Copy and assign are allowed for easy use with STL containers. + }; + + // The list of registered persistent allocators, described by RecordAllocator + // instances. + std::vector<RecordAllocator> allocators_; + + THREAD_CHECKER(thread_checker_); + + DISALLOW_COPY_AND_ASSIGN(PersistentSystemProfile); +}; + +// A singleton instance of the above. +class GlobalPersistentSystemProfile : public PersistentSystemProfile { + public: + static GlobalPersistentSystemProfile* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits<GlobalPersistentSystemProfile>; + + GlobalPersistentSystemProfile() {} + ~GlobalPersistentSystemProfile() {} + + DISALLOW_COPY_AND_ASSIGN(GlobalPersistentSystemProfile); +}; + +} // namespace metrics + +#endif // BASE_METRICS_PERSISTENT_SYSTEM_PROFILE_H_
diff --git a/components/metrics/persistent_system_profile_unittest.cc b/components/metrics/persistent_system_profile_unittest.cc new file mode 100644 index 0000000..93f297a --- /dev/null +++ b/components/metrics/persistent_system_profile_unittest.cc
@@ -0,0 +1,123 @@ +// 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/metrics/persistent_system_profile.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/persistent_memory_allocator.h" +#include "base/rand_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace metrics { + +class PersistentSystemProfileTest : public testing::Test { + public: + const int32_t kAllocatorMemorySize = 1 << 20; // 1 MiB + + PersistentSystemProfileTest() {} + ~PersistentSystemProfileTest() override {} + + void SetUp() override { + memory_allocator_ = base::MakeUnique<base::LocalPersistentMemoryAllocator>( + kAllocatorMemorySize, 0, ""); + records_ = base::MakeUnique<PersistentSystemProfile::RecordAllocator>( + memory_allocator_.get()); + persistent_profile_.RegisterPersistentAllocator(memory_allocator_.get()); + } + + void TearDown() override { + persistent_profile_.DeregisterPersistentAllocator(memory_allocator_.get()); + records_.reset(); + memory_allocator_.reset(); + } + + void WriteRecord(uint8_t type, const std::string& record) { + persistent_profile_.allocators_[0].Write( + static_cast<PersistentSystemProfile::RecordType>(type), record); + } + + bool ReadRecord(uint8_t* type, std::string* record) { + PersistentSystemProfile::RecordType rec_type; + + bool success = records_->Read(&rec_type, record); + *type = rec_type; // Convert to uint8_t for testing. + return success; + } + + base::PersistentMemoryAllocator* memory_allocator() { + return memory_allocator_.get(); + } + + PersistentSystemProfile* persistent_profile() { return &persistent_profile_; } + + private: + PersistentSystemProfile persistent_profile_; + std::unique_ptr<base::PersistentMemoryAllocator> memory_allocator_; + std::unique_ptr<PersistentSystemProfile::RecordAllocator> records_; + + DISALLOW_COPY_AND_ASSIGN(PersistentSystemProfileTest); +}; + +TEST_F(PersistentSystemProfileTest, Create) { + uint32_t type; + base::PersistentMemoryAllocator::Iterator iter(memory_allocator()); + base::PersistentMemoryAllocator::Reference ref = iter.GetNext(&type); + DCHECK(ref); + DCHECK_NE(0U, type); +} + +TEST_F(PersistentSystemProfileTest, RecordSplitting) { + const size_t kRecordSize = 100 << 10; // 100 KiB + std::vector<char> buffer; + buffer.resize(kRecordSize); + base::RandBytes(&buffer[0], kRecordSize); + + WriteRecord(42, std::string(&buffer[0], kRecordSize)); + + uint8_t type; + std::string record; + ASSERT_TRUE(ReadRecord(&type, &record)); + EXPECT_EQ(42U, type); + ASSERT_EQ(kRecordSize, record.size()); + for (size_t i = 0; i < kRecordSize; ++i) + EXPECT_EQ(buffer[i], record[i]); +} + +TEST_F(PersistentSystemProfileTest, ProfileStorage) { + SystemProfileProto proto1; + SystemProfileProto::FieldTrial* trial = proto1.add_field_trial(); + trial->set_name_id(123); + trial->set_group_id(456); + + std::string serialized_proto; + ASSERT_TRUE(proto1.SerializeToString(&serialized_proto)); + persistent_profile()->SetSystemProfile(serialized_proto); + + SystemProfileProto proto2; + ASSERT_TRUE( + PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2)); + ASSERT_EQ(1, proto2.field_trial_size()); + EXPECT_EQ(123U, proto2.field_trial(0).name_id()); + EXPECT_EQ(456U, proto2.field_trial(0).group_id()); + + // Check that the profile can be overwritten. + + trial = proto1.add_field_trial(); + trial->set_name_id(78); + trial->set_group_id(90); + + ASSERT_TRUE(proto1.SerializeToString(&serialized_proto)); + persistent_profile()->SetSystemProfile(serialized_proto); + + ASSERT_TRUE( + PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2)); + ASSERT_EQ(2, proto2.field_trial_size()); + EXPECT_EQ(123U, proto2.field_trial(0).name_id()); + EXPECT_EQ(456U, proto2.field_trial(0).group_id()); + EXPECT_EQ(78U, proto2.field_trial(1).name_id()); + EXPECT_EQ(90U, proto2.field_trial(1).group_id()); +} + +} // namespace metrics
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.cc b/components/password_manager/core/browser/password_reuse_detection_manager.cc index f549345c..dba2a52c 100644 --- a/components/password_manager/core/browser/password_reuse_detection_manager.cc +++ b/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -4,24 +4,30 @@ #include "components/password_manager/core/browser/password_reuse_detection_manager.h" +#include "base/time/default_clock.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_client.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_manager_util.h" +#include "ui/events/keycodes/keyboard_codes_posix.h" #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE) #include "components/safe_browsing/password_protection/password_protection_service.h" #endif +using base::Time; +using base::TimeDelta; + namespace password_manager { namespace { constexpr size_t kMaxNumberOfCharactersToStore = 30; +constexpr TimeDelta kMaxInactivityTime = TimeDelta::FromSeconds(10); } PasswordReuseDetectionManager::PasswordReuseDetectionManager( PasswordManagerClient* client) - : client_(client) { + : client_(client), clock_(new base::DefaultClock) { DCHECK(client_); } @@ -34,6 +40,20 @@ } void PasswordReuseDetectionManager::OnKeyPressed(const base::string16& text) { + // Clear the buffer if last keystoke was more than kMaxInactivityTime ago. + Time now = clock_->Now(); + if (!last_keystroke_time_.is_null() && + (now - last_keystroke_time_) >= kMaxInactivityTime) { + input_characters_.clear(); + } + last_keystroke_time_ = now; + + // Clear the buffer and return when enter is pressed. + if (text.size() == 1 && text[0] == ui::VKEY_RETURN) { + input_characters_.clear(); + return; + } + input_characters_ += text; if (input_characters_.size() > kMaxNumberOfCharactersToStore) { input_characters_.erase( @@ -70,4 +90,9 @@ #endif } +void PasswordReuseDetectionManager::SetClockForTesting( + std::unique_ptr<base::Clock> clock) { + clock_ = std::move(clock); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.h b/components/password_manager/core/browser/password_reuse_detection_manager.h index 9aba12b..f6e1fd4 100644 --- a/components/password_manager/core/browser/password_reuse_detection_manager.h +++ b/components/password_manager/core/browser/password_reuse_detection_manager.h
@@ -7,9 +7,14 @@ #include "base/macros.h" #include "base/strings/string16.h" +#include "base/time/time.h" #include "components/password_manager/core/browser/password_reuse_detector_consumer.h" #include "url/gurl.h" +namespace base { +class Clock; +} + namespace password_manager { class PasswordManagerClient; @@ -30,10 +35,15 @@ int saved_passwords, int number_matches) override; + void SetClockForTesting(std::unique_ptr<base::Clock> clock); + private: PasswordManagerClient* client_; base::string16 input_characters_; GURL main_frame_url_; + base::Time last_keystroke_time_; + // Used to retrieve the current time, in base::Time units. + std::unique_ptr<base::Clock> clock_; DISALLOW_COPY_AND_ASSIGN(PasswordReuseDetectionManager); };
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc b/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc index d166a5b6..151c1fa 100644 --- a/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc +++ b/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
@@ -7,10 +7,12 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_task_environment.h" +#include "base/test/simple_test_clock.h" #include "components/password_manager/core/browser/mock_password_store.h" #include "components/password_manager/core/browser/stub_password_manager_client.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/keycodes/keyboard_codes_posix.h" #include "url/gurl.h" using base::ASCIIToUTF16; @@ -86,6 +88,48 @@ } } +// Verify that the keystroke buffer is cleared after 10 seconds of user +// inactivity. +TEST_F(PasswordReuseDetectionManagerTest, + CheckThatBufferClearedAfterInactivity) { + EXPECT_CALL(client_, GetPasswordStore()) + .WillRepeatedly(testing::Return(store_.get())); + PasswordReuseDetectionManager manager(&client_); + + std::unique_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + base::Time now = base::Time::Now(); + clock->SetNow(now); + base::SimpleTestClock* clock_weak = clock.get(); + manager.SetClockForTesting(std::move(clock)); + + EXPECT_CALL(*store_, CheckReuse(base::ASCIIToUTF16("1"), _, _)); + manager.OnKeyPressed(base::ASCIIToUTF16("1")); + + // Simulate 10 seconds of inactivity. + clock_weak->SetNow(now + base::TimeDelta::FromSeconds(10)); + // Expect that a keystroke typed before inactivity is cleared. + EXPECT_CALL(*store_, CheckReuse(base::ASCIIToUTF16("2"), _, _)); + manager.OnKeyPressed(base::ASCIIToUTF16("2")); +} + +// Verify that the keystroke buffer is cleared after user presses enter. +TEST_F(PasswordReuseDetectionManagerTest, CheckThatBufferClearedAfterEnter) { + EXPECT_CALL(client_, GetPasswordStore()) + .WillRepeatedly(testing::Return(store_.get())); + PasswordReuseDetectionManager manager(&client_); + + EXPECT_CALL(*store_, CheckReuse(base::ASCIIToUTF16("1"), _, _)); + manager.OnKeyPressed(base::ASCIIToUTF16("1")); + + base::string16 enter_text(1, ui::VKEY_RETURN); + EXPECT_CALL(*store_, CheckReuse(_, _, _)).Times(0); + manager.OnKeyPressed(enter_text); + + // Expect only a keystroke typed after enter. + EXPECT_CALL(*store_, CheckReuse(base::ASCIIToUTF16("2"), _, _)); + manager.OnKeyPressed(base::ASCIIToUTF16("2")); +} + } // namespace } // namespace password_manager
diff --git a/components/translate/ios/browser/js_translate_manager.mm b/components/translate/ios/browser/js_translate_manager.mm index aa5df282..6e36d713 100644 --- a/components/translate/ios/browser/js_translate_manager.mm +++ b/components/translate/ios/browser/js_translate_manager.mm
@@ -34,9 +34,6 @@ @"performance.now = performance['now'] ||" @"(function () { return Date.now(); });\n"; script = [kPerformancePlaceholder stringByAppendingString:script]; - // TODO(shreyasv): This leads to some duplicate code from - // CRWJSInjectionManager. Consider refactoring this to its own js injection - // manager. NSString* path = [base::mac::FrameworkBundle() pathForResource:@"translate_ios" ofType:@"js"];
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 6015c1cf..0d87a7d 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -41,7 +41,7 @@ terminate_child_on_shutdown_(terminate_on_shutdown), #endif weak_factory_(this) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); helper_ = new ChildProcessLauncherHelper( @@ -52,7 +52,7 @@ } ChildProcessLauncher::~ChildProcessLauncher() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (process_.process.IsValid() && terminate_child_on_shutdown_) { // Client has gone away, so just kill the process. ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync( @@ -62,7 +62,7 @@ void ChildProcessLauncher::SetProcessPriority(bool background, bool boost_for_pending_views) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::Process to_pass = process_.process.Duplicate(); BrowserThread::PostTask( BrowserThread::PROCESS_LAUNCHER, FROM_HERE, @@ -76,7 +76,7 @@ ChildProcessLauncherHelper::Process process, mojo::edk::ScopedPlatformHandle server_handle, int error_code) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); starting_ = false; process_ = std::move(process); @@ -103,20 +103,20 @@ bool ChildProcessLauncher::IsStarting() { // TODO(crbug.com/469248): This fails in some tests. - // DCHECK(CalledOnValidThread()); + // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return starting_; } const base::Process& ChildProcessLauncher::GetProcess() const { // TODO(crbug.com/469248): This fails in some tests. - // DCHECK(CalledOnValidThread()); + // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return process_.process; } base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( bool known_dead, int* exit_code) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!process_.process.IsValid()) { // Process is already gone, so return the cached termination status. if (exit_code)
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index 736a734..074f2cf 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h
@@ -13,7 +13,7 @@ #include "base/memory/weak_ptr.h" #include "base/process/kill.h" #include "base/process/process.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "build/build_config.h" #include "content/browser/child_process_launcher_helper.h" #include "content/common/content_export.h" @@ -52,7 +52,7 @@ // Launches a process asynchronously and notifies the client of the process // handle when it's available. It's used to avoid blocking the calling thread // on the OS since often it can take > 100 ms to create the process. -class CONTENT_EXPORT ChildProcessLauncher : public base::NonThreadSafe { +class CONTENT_EXPORT ChildProcessLauncher { public: class CONTENT_EXPORT Client { public: @@ -172,6 +172,8 @@ scoped_refptr<internal::ChildProcessLauncherHelper> helper_; + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<ChildProcessLauncher> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ChildProcessLauncher);
diff --git a/content/public/browser/notification_registrar.cc b/content/public/browser/notification_registrar.cc index 21a2167..1890089 100644 --- a/content/public/browser/notification_registrar.cc +++ b/content/public/browser/notification_registrar.cc
@@ -36,17 +36,18 @@ NotificationServiceImpl::current(); // It is OK to create a NotificationRegistrar instance on one thread and then // use it (exclusively) on another, so we detach from the initial thread. - DetachFromThread(); + DETACH_FROM_SEQUENCE(sequence_checker_); } NotificationRegistrar::~NotificationRegistrar() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); RemoveAll(); } void NotificationRegistrar::Add(NotificationObserver* observer, int type, const NotificationSource& source) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsRegistered(observer, type, source)) << "Duplicate registration."; Record record = { observer, type, source }; @@ -58,7 +59,7 @@ void NotificationRegistrar::Remove(NotificationObserver* observer, int type, const NotificationSource& source) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); Record record = { observer, type, source }; RecordVector::iterator found = std::find( @@ -75,7 +76,7 @@ } void NotificationRegistrar::RemoveAll() { - CHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Early-exit if no registrations, to avoid calling // NotificationService::current. If we've constructed an object with a // NotificationRegistrar member, but haven't actually used the notification @@ -99,14 +100,14 @@ } bool NotificationRegistrar::IsEmpty() const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return registered_.empty(); } bool NotificationRegistrar::IsRegistered(NotificationObserver* observer, int type, const NotificationSource& source) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); Record record = { observer, type, source }; return std::find(registered_.begin(), registered_.end(), record) != registered_.end();
diff --git a/content/public/browser/notification_registrar.h b/content/public/browser/notification_registrar.h index 9097f8f..8f78542 100644 --- a/content/public/browser/notification_registrar.h +++ b/content/public/browser/notification_registrar.h
@@ -8,7 +8,7 @@ #include <vector> #include "base/macros.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "content/common/content_export.h" namespace content { @@ -23,8 +23,7 @@ // class and use it to register your notifications instead of going through the // notification service directly. It will automatically unregister them for // you. -class CONTENT_EXPORT NotificationRegistrar : - NON_EXPORTED_BASE(public base::NonThreadSafe) { +class CONTENT_EXPORT NotificationRegistrar { public: // This class must not be derived from (we don't have a virtual destructor so // it won't work). Instead, use it as a member in your class. @@ -63,6 +62,8 @@ // Lists all notifications we're currently registered for. RecordVector registered_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(NotificationRegistrar); };
diff --git a/gin/BUILD.gn b/gin/BUILD.gn index f386fb6b..212acaeb 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn
@@ -103,7 +103,6 @@ deps = [ ":gin_features", "//base/third_party/dynamic_annotations", - "//crypto", ] if (is_mac) {
diff --git a/gin/DEPS b/gin/DEPS index d4cc2ba..4e3f30a 100644 --- a/gin/DEPS +++ b/gin/DEPS
@@ -1,5 +1,4 @@ include_rules = [ "+base", - "+crypto", "+v8", ]
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc index 726d7c04..ce062ac0 100644 --- a/gin/v8_initializer.cc +++ b/gin/v8_initializer.cc
@@ -23,7 +23,6 @@ #include "base/sys_info.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "crypto/sha2.h" #include "gin/public/gin_features.h" #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.mm b/ios/chrome/browser/snapshots/snapshot_cache.mm index 612dc57e..ab03a7f 100644 --- a/ios/chrome/browser/snapshots/snapshot_cache.mm +++ b/ios/chrome/browser/snapshots/snapshot_cache.mm
@@ -10,7 +10,6 @@ #include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" #include "base/mac/bind_objc_block.h" @@ -19,7 +18,6 @@ #include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "base/task_runner_util.h" -#include "base/task_scheduler/post_task.h" #include "base/threading/thread_restrictions.h" #include "ios/chrome/browser/experimental_flags.h" #import "ios/chrome/browser/snapshots/lru_cache.h" @@ -33,11 +31,11 @@ + (base::FilePath)cacheDirectory; // Returns the directory where the thumbnails were stored in M28 and earlier. - (base::FilePath)oldCacheDirectory; -// Remove all UIImages from |imageDictionary_|. +// Remove all UIImages from |lruCache_|. - (void)handleEnterBackground; -// Remove all but adjacent UIImages from |imageDictionary_|. +// Remove all but adjacent UIImages from |lruCache_|. - (void)handleLowMemory; -// Restore adjacent UIImages to |imageDictionary_|. +// Restore adjacent UIImages to |lruCache_|. - (void)handleBecomeActive; // Clear most recent caller information. - (void)clearGreySessionInfo; @@ -51,23 +49,14 @@ namespace { static NSArray* const kSnapshotCacheDirectory = @[ @"Chromium", @"Snapshots" ]; -const NSUInteger kCacheInitialCapacity = 100; const NSUInteger kGreyInitialCapacity = 8; const CGFloat kJPEGImageQuality = 1.0; // Highest quality. No compression. +// Sequence token to make sure creation/deletion of snapshots don't overlap. +const char kSequenceToken[] = "SnapshotCacheSequenceToken"; // Maximum size in number of elements that the LRU cache can hold before // starting to evict elements. const NSUInteger kLRUCacheMaxCapacity = 6; -struct SnapshotTaskRunner { - const scoped_refptr<base::SequencedTaskRunner> task_runner = - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); -}; - -// Sequence token to make sure creation/deletion of snapshots don't overlap. -base::LazyInstance<SnapshotTaskRunner>::Leaky g_snapshot_task_runner = - LAZY_INSTANCE_INITIALIZER; - // The paths of the images saved to disk, given a cache directory. base::FilePath FilePathForSessionID(NSString* sessionID, const base::FilePath& directory) { @@ -143,13 +132,8 @@ } // anonymous namespace @implementation SnapshotCache { - // Dictionary to hold color snapshots in memory. n.b. Color snapshots are not - // kept in memory on tablets. - base::scoped_nsobject<NSMutableDictionary> imageDictionary_; - // Cache to hold color snapshots in memory. n.b. Color snapshots are not - // kept in memory on tablets. It is used in place of the imageDictionary_ when - // the LRU cache snapshot experiment is enabled. + // kept in memory on tablets. base::scoped_nsobject<LRUCache> lruCache_; // Temporary dictionary to hold grey snapshots for tablet side swipe. This @@ -183,13 +167,7 @@ DCHECK_CURRENTLY_ON(web::WebThread::UI); propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); - if ([self usesLRUCache]) { - lruCache_.reset( - [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); - } else { - imageDictionary_.reset( - [[NSMutableDictionary alloc] initWithCapacity:kCacheInitialCapacity]); - } + lruCache_.reset([[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleLowMemory) @@ -242,15 +220,10 @@ DCHECK_CURRENTLY_ON(web::WebThread::UI); DCHECK(sessionID); - UIImage* img = nil; - if (lruCache_) - img = [lruCache_ objectForKey:sessionID]; - else - img = [imageDictionary_ objectForKey:sessionID]; - - if (img) { + UIImage* image = [lruCache_ objectForKey:sessionID]; + if (image) { if (callback) - callback(img); + callback(image); return; } @@ -263,45 +236,36 @@ [SnapshotCache imagePathForSessionID:sessionID]) retain]); }), base::BindBlock(^(base::scoped_nsobject<UIImage> image) { - if (image) { - if (lruCache_) - [lruCache_ setObject:image forKey:sessionID]; - else - [imageDictionary_ setObject:image forKey:sessionID]; - } + if (image) + [lruCache_ setObject:image forKey:sessionID]; if (callback) callback(image); })); } -- (void)setImage:(UIImage*)img withSessionID:(NSString*)sessionID { +- (void)setImage:(UIImage*)image withSessionID:(NSString*)sessionID { DCHECK_CURRENTLY_ON(web::WebThread::UI); - if (!img || !sessionID) + if (!image || !sessionID) return; - if (lruCache_) - [lruCache_ setObject:img forKey:sessionID]; - else - [imageDictionary_ setObject:img forKey:sessionID]; + [lruCache_ setObject:image forKey:sessionID]; // Save the image to disk. - g_snapshot_task_runner.Get().task_runner->PostTask( - FROM_HERE, base::BindBlock(^{ - base::scoped_nsobject<UIImage> image([img retain]); - WriteImageToDisk(image, + web::WebThread::PostBlockingPoolSequencedTask( + kSequenceToken, FROM_HERE, base::BindBlock(^{ + base::scoped_nsobject<UIImage> scoped_image([image retain]); + WriteImageToDisk(scoped_image, [SnapshotCache imagePathForSessionID:sessionID]); })); } - (void)removeImageWithSessionID:(NSString*)sessionID { DCHECK_CURRENTLY_ON(web::WebThread::UI); - if (lruCache_) - [lruCache_ removeObjectForKey:sessionID]; - else - [imageDictionary_ removeObjectForKey:sessionID]; + [lruCache_ removeObjectForKey:sessionID]; - g_snapshot_task_runner.Get().task_runner->PostTask( - FROM_HERE, base::BindBlock(^{ + web::WebThread::PostBlockingPoolSequencedTask( + kSequenceToken, FROM_HERE, + base::BindBlock(^{ base::FilePath imagePath = [SnapshotCache imagePathForSessionID:sessionID]; base::DeleteFile(imagePath, false); @@ -365,8 +329,9 @@ DCHECK_CURRENTLY_ON(web::WebThread::UI); // Copying the date, as the block must copy the value, not the reference. const base::Time dateCopy = date; - g_snapshot_task_runner.Get().task_runner->PostTask( - FROM_HERE, base::BindBlock(^{ + web::WebThread::PostBlockingPoolSequencedTask( + kSequenceToken, FROM_HERE, + base::BindBlock(^{ std::set<base::FilePath> filesToKeep; for (NSString* sessionID : liveSessionIds) { base::FilePath curImagePath = @@ -398,17 +363,7 @@ if (!sessionID) return; backgroundingImageSessionId_.reset([sessionID copy]); - if (lruCache_) { - backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); - } else { - backgroundingColorImage_.reset( - [[imageDictionary_ objectForKey:sessionID] retain]); - } -} - -- (BOOL)usesLRUCache { - // TODO(crbug.com/687904): Remove the non-LRU cache code. - return true; + backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); } - (void)handleLowMemory { @@ -416,27 +371,17 @@ base::scoped_nsobject<NSMutableDictionary> dictionary( [[NSMutableDictionary alloc] initWithCapacity:2]); for (NSString* sessionID in pinnedIDs_) { - UIImage* image = nil; - if (lruCache_) - image = [lruCache_ objectForKey:sessionID]; - else - image = [imageDictionary_ objectForKey:sessionID]; + UIImage* image = [lruCache_ objectForKey:sessionID]; if (image) [dictionary setObject:image forKey:sessionID]; } - if (lruCache_) { - [lruCache_ removeAllObjects]; - for (NSString* sessionID in pinnedIDs_) - [lruCache_ setObject:[dictionary objectForKey:sessionID] - forKey:sessionID]; - } else { - imageDictionary_ = dictionary; - } + [lruCache_ removeAllObjects]; + for (NSString* sessionID in pinnedIDs_) + [lruCache_ setObject:[dictionary objectForKey:sessionID] forKey:sessionID]; } - (void)handleEnterBackground { DCHECK_CURRENTLY_ON(web::WebThread::UI); - [imageDictionary_ removeAllObjects]; [lruCache_ removeAllObjects]; } @@ -461,17 +406,13 @@ // Don't call -retrieveImageForSessionID here because it caches the colored // image, which we don't need for the grey image cache. But if the image is // already in the cache, use it. - UIImage* img = nil; - if (lruCache_) - img = [lruCache_ objectForKey:sessionID]; - else - img = [imageDictionary_ objectForKey:sessionID]; + UIImage* image = [lruCache_ objectForKey:sessionID]; base::PostTaskAndReplyWithResult( web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING) .get(), FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() { - base::scoped_nsobject<UIImage> result([img retain]); + base::scoped_nsobject<UIImage> result([image retain]); // If the image is not in the cache, load it from disk. if (!result) result.reset([ReadImageFromDisk( @@ -553,9 +494,9 @@ base::BindBlock(^(base::scoped_nsobject<UIImage> image) { if (!image) { [self retrieveImageForSessionID:sessionID - callback:^(UIImage* img) { - if (callback && img) - callback(GreyImage(img)); + callback:^(UIImage* local_image) { + if (callback && local_image) + callback(GreyImage(local_image)); }]; } else if (callback) { callback(image); @@ -581,10 +522,9 @@ } } - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&ConvertAndSaveGreyImage, colorImagePath, greyImagePath, - backgroundingColorImage_)); + web::WebThread::PostBlockingPoolTask( + FROM_HERE, base::Bind(&ConvertAndSaveGreyImage, colorImagePath, + greyImagePath, backgroundingColorImage_)); } @end @@ -592,10 +532,7 @@ @implementation SnapshotCache (TestingAdditions) - (BOOL)hasImageInMemory:(NSString*)sessionID { - if ([self usesLRUCache]) - return [lruCache_ objectForKey:sessionID] != nil; - else - return [imageDictionary_ objectForKey:sessionID] != nil; + return [lruCache_ objectForKey:sessionID] != nil; } - (BOOL)hasGreyImageInMemory:(NSString*)sessionID {
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_internal.h b/ios/chrome/browser/snapshots/snapshot_cache_internal.h index dcc2e8f..2283f66 100644 --- a/ios/chrome/browser/snapshots/snapshot_cache_internal.h +++ b/ios/chrome/browser/snapshots/snapshot_cache_internal.h
@@ -18,8 +18,6 @@ + (base::FilePath)imagePathForSessionID:(NSString*)sessionID; // Returns filepath to the greyscale snapshot of |sessionID|. + (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID; -// Returns whether the snapshots are cached in a LRU cache. -- (BOOL)usesLRUCache; @end #endif // IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_CACHE_INTERNAL_H_
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm index 500f9422..4c1c2be 100644 --- a/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm +++ b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm
@@ -16,10 +16,11 @@ #include "base/mac/scoped_nsobject.h" #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" -#include "base/task_scheduler/task_scheduler.h" +#include "base/threading/sequenced_worker_pool.h" #include "base/time/time.h" #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h" #include "ios/web/public/test/test_web_thread_bundle.h" +#include "ios/web/public/web_thread.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h" #include "testing/platform_test.h" @@ -83,7 +84,7 @@ // Flushes all the runloops internally used by the snapshot cache. void FlushRunLoops() { base::RunLoop().RunUntilIdle(); - base::TaskScheduler::GetInstance()->FlushForTesting(); + web::WebThread::GetBlockingPool()->FlushForTesting(); base::RunLoop().RunUntilIdle(); } @@ -214,9 +215,7 @@ TEST_F(SnapshotCacheTest, Cache) { SnapshotCache* cache = GetSnapshotCache(); - NSUInteger expectedCacheSize = kSessionCount; - if ([cache usesLRUCache]) - expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); + NSUInteger expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); // Put all images in the cache. for (NSUInteger i = 0; i < expectedCacheSize; ++i) {
diff --git a/ios/chrome/browser/translate/js_language_detection_manager_unittest.mm b/ios/chrome/browser/translate/js_language_detection_manager_unittest.mm index 6ec7d42..a1db1f8 100644 --- a/ios/chrome/browser/translate/js_language_detection_manager_unittest.mm +++ b/ios/chrome/browser/translate/js_language_detection_manager_unittest.mm
@@ -37,7 +37,6 @@ } // namespace -// TODO(shreyasv): Moved this to the translate component. // Test fixture to test language detection. class JsLanguageDetectionManagerTest : public ChromeWebTest { protected:
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller_unittest.mm index 8772468..75cf9be 100644 --- a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller_unittest.mm
@@ -247,8 +247,8 @@ int cache_size; NSString* expected_output; } kTestCases[] = { - {0, @"less than 1 MB"}, - {(1 << 20) - 1, @"less than 1 MB"}, + {0, @"Less than 1 MB"}, + {(1 << 20) - 1, @"Less than 1 MB"}, {(1 << 20), @"1 MB"}, {(1 << 20) + (1 << 19), @"1.5 MB"}, {(1 << 21), @"2 MB"}, @@ -287,12 +287,12 @@ int cache_size; NSString* expected_output; } kTestCases[] = { - {0, @"less than 1 MB"}, - {(1 << 20) - 1, @"less than 1 MB"}, - {(1 << 20), @"less than 1 MB"}, - {(1 << 20) + (1 << 19), @"less than 1.5 MB"}, - {(1 << 21), @"less than 2 MB"}, - {(1 << 30), @"less than 1 GB"} + {0, @"Less than 1 MB"}, + {(1 << 20) - 1, @"Less than 1 MB"}, + {(1 << 20), @"Less than 1 MB"}, + {(1 << 20) + (1 << 19), @"Less than 1.5 MB"}, + {(1 << 21), @"Less than 2 MB"}, + {(1 << 30), @"Less than 1 GB"} }; // clang-format on
diff --git a/ios/web/public/web_thread.h b/ios/web/public/web_thread.h index 0ab786c..be41b30 100644 --- a/ios/web/public/web_thread.h +++ b/ios/web/public/web_thread.h
@@ -139,6 +139,38 @@ return GetTaskRunnerForThread(identifier)->DeleteSoon(from_here, object); } + // Simplified wrappers for posting to the blocking thread pool. Use this + // for doing things like blocking I/O. + // + // The first variant will run the task in the pool with no sequencing + // semantics, so may get run in parallel with other posted tasks. The second + // variant will all post a task with no sequencing semantics, and will post a + // reply task to the origin TaskRunner upon completion. The third variant + // provides sequencing between tasks with the same sequence token name. + // + // These tasks are guaranteed to run before shutdown. + // + // If you need to provide different shutdown semantics (like you have + // something slow and noncritical that doesn't need to block shutdown), + // or you want to manually provide a sequence token (which saves a map + // lookup and is guaranteed unique without you having to come up with a + // unique string), you can access the sequenced worker pool directly via + // GetBlockingPool(). + // + // If you need to PostTaskAndReplyWithResult, use + // base::PostTaskAndReplyWithResult() with GetBlockingPool() as the task + // runner. + static bool PostBlockingPoolTask(const tracked_objects::Location& from_here, + base::OnceClosure task); + static bool PostBlockingPoolTaskAndReply( + const tracked_objects::Location& from_here, + base::OnceClosure task, + base::OnceClosure reply); + static bool PostBlockingPoolSequencedTask( + const std::string& sequence_token_name, + const tracked_objects::Location& from_here, + base::OnceClosure task); + // Returns the thread pool used for blocking file I/O. Use this object to // perform random blocking operations such as file writes. static base::SequencedWorkerPool* GetBlockingPool() WARN_UNUSED_RESULT;
diff --git a/ios/web/web_state/navigation_callbacks_inttest.mm b/ios/web/web_state/navigation_callbacks_inttest.mm index 0b18bd3c..ac78fd2 100644 --- a/ios/web/web_state/navigation_callbacks_inttest.mm +++ b/ios/web/web_state/navigation_callbacks_inttest.mm
@@ -42,6 +42,7 @@ EXPECT_FALSE((*context)->IsPost()); EXPECT_FALSE((*context)->GetError()); ASSERT_FALSE((*context)->GetResponseHeaders()); + ASSERT_TRUE(web_state->IsLoading()); NavigationManager* navigation_manager = web_state->GetNavigationManager(); NavigationItem* item = navigation_manager->GetPendingItem(); EXPECT_EQ(url, item->GetURL()); @@ -65,6 +66,7 @@ ASSERT_TRUE((*context)->GetResponseHeaders()); std::string mime_type; (*context)->GetResponseHeaders()->GetMimeType(&mime_type); + ASSERT_TRUE(web_state->IsLoading()); EXPECT_EQ(kExpectedMimeType, mime_type); NavigationManager* navigation_manager = web_state->GetNavigationManager(); NavigationItem* item = navigation_manager->GetLastCommittedItem(); @@ -84,6 +86,7 @@ EXPECT_TRUE((*context)->IsPost()); EXPECT_FALSE((*context)->GetError()); ASSERT_FALSE((*context)->GetResponseHeaders()); + ASSERT_TRUE(web_state->IsLoading()); // TODO(crbug.com/676129): Reload does not create a pending item. Remove this // workaround once the bug is fixed. if (!ui::PageTransitionTypeIncludingQualifiersIs( @@ -107,6 +110,7 @@ EXPECT_FALSE((*context)->IsSameDocument()); EXPECT_TRUE((*context)->IsPost()); EXPECT_FALSE((*context)->GetError()); + ASSERT_TRUE(web_state->IsLoading()); NavigationManager* navigation_manager = web_state->GetNavigationManager(); NavigationItem* item = navigation_manager->GetLastCommittedItem(); EXPECT_GT(item->GetTimestamp().ToInternalValue(), 0); @@ -172,6 +176,7 @@ EXPECT_FALSE((*context)->IsPost()); EXPECT_FALSE((*context)->GetError()); EXPECT_FALSE((*context)->GetResponseHeaders()); + ASSERT_TRUE(web_state->IsLoading()); NavigationManager* navigation_manager = web_state->GetNavigationManager(); NavigationItem* item = navigation_manager->GetPendingItem(); EXPECT_EQ(url, item->GetURL()); @@ -250,27 +255,31 @@ WebStateObserverMock(WebState* web_state) : WebStateObserver(web_state) {} MOCK_METHOD1(DidStartNavigation, void(NavigationContext* context)); MOCK_METHOD1(DidFinishNavigation, void(NavigationContext* context)); + MOCK_METHOD0(DidStartLoading, void()); + MOCK_METHOD0(DidStopLoading, void()); }; } // namespace using test::HttpServer; +using testing::StrictMock; using testing::_; -// Test fixture for WebStateDelegate::ProvisionalNavigationStarted and -// WebStateDelegate::DidFinishNavigation integration tests. -class StartAndFinishNavigationTest : public WebIntTest { +// Test fixture for WebStateDelegate::ProvisionalNavigationStarted, +// WebStateDelegate::DidFinishNavigation, WebStateDelegate::DidStartLoading and +// WebStateDelegate::DidStopLoading integration tests. +class NavigationCallbacksTest : public WebIntTest { void SetUp() override { WebIntTest::SetUp(); - observer_ = base::MakeUnique<WebStateObserverMock>(web_state()); + observer_ = base::MakeUnique<StrictMock<WebStateObserverMock>>(web_state()); } protected: - std::unique_ptr<WebStateObserverMock> observer_; + std::unique_ptr<StrictMock<WebStateObserverMock>> observer_; }; // Tests successful navigation to a new page. -TEST_F(StartAndFinishNavigationTest, NewPageNavigation) { +TEST_F(NavigationCallbacksTest, NewPageNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -280,13 +289,15 @@ NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyNewPageStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); } // Tests web page reload navigation. -TEST_F(StartAndFinishNavigationTest, WebPageReloadNavigation) { +TEST_F(NavigationCallbacksTest, WebPageReloadNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -295,15 +306,19 @@ // Perform new page navigation. NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Reload web page. EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyReloadStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyReloadFinishedContext(web_state(), url, &context, true /* is_web_page */)); + EXPECT_CALL(*observer_, DidStopLoading()); // TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current // delegate does not run callback for ShowRepostFormWarningDialog. Clearing // the delegate will allow form resubmission. Remove this workaround (clearing @@ -316,7 +331,7 @@ } // Tests user-initiated hash change. -TEST_F(StartAndFinishNavigationTest, UserInitiatedHashChangeNavigation) { +TEST_F(NavigationCallbacksTest, UserInitiatedHashChangeNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -326,8 +341,10 @@ NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyNewPageStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Perform same-page navigation. @@ -336,10 +353,12 @@ .WillOnce(VerifySameDocumentStartedContext( web_state(), hash_url, &context, ui::PageTransition::PAGE_TRANSITION_TYPED)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifySameDocumentFinishedContext( web_state(), hash_url, &context, ui::PageTransition::PAGE_TRANSITION_TYPED)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(hash_url); // Perform same-page navigation by going back. @@ -347,17 +366,19 @@ .WillOnce(VerifySameDocumentStartedContext( web_state(), url, &context, ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifySameDocumentFinishedContext( web_state(), url, &context, ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteBlockAndWaitForLoad(url, ^{ navigation_manager()->GoBack(); }); } // Tests renderer-initiated hash change. -TEST_F(StartAndFinishNavigationTest, RendererInitiatedHashChangeNavigation) { +TEST_F(NavigationCallbacksTest, RendererInitiatedHashChangeNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -367,8 +388,10 @@ NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyNewPageStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Perform same-page navigation using JavaScript. @@ -377,15 +400,17 @@ .WillOnce(VerifySameDocumentStartedContext( web_state(), hash_url, &context, ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifySameDocumentFinishedContext( web_state(), hash_url, &context, ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteJavaScript(@"window.location.hash = '#1'"); } // Tests state change. -TEST_F(StartAndFinishNavigationTest, StateNavigation) { +TEST_F(NavigationCallbacksTest, StateNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -395,8 +420,10 @@ NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyNewPageStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyNewPageFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Perform push state using JavaScript. @@ -425,35 +452,41 @@ } // Tests native content navigation. -TEST_F(StartAndFinishNavigationTest, NativeContentNavigation) { +TEST_F(NavigationCallbacksTest, NativeContentNavigation) { GURL url(url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize()); NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyNewNativePageStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyNewNativePageFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); } // Tests native content reload navigation. -TEST_F(StartAndFinishNavigationTest, NativeContentReload) { +TEST_F(NavigationCallbacksTest, NativeContentReload) { GURL url(url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize()); NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Reload native content. EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyReloadStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyReloadFinishedContext(web_state(), url, &context, false /* is_web_page */)); + EXPECT_CALL(*observer_, DidStopLoading()); navigation_manager()->Reload(ReloadType::NORMAL, false /*check_for_repost*/); } // Tests successful navigation to a new page with post HTTP method. -TEST_F(StartAndFinishNavigationTest, UserInitiatedPostNavigation) { +TEST_F(NavigationCallbacksTest, UserInitiatedPostNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "Chromium Test"; @@ -463,8 +496,10 @@ NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyPostStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyPostFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); // Load request using POST HTTP method. web::NavigationManager::WebLoadParams params(url); @@ -475,7 +510,7 @@ } // Tests successful navigation to a new page with post HTTP method. -TEST_F(StartAndFinishNavigationTest, RendererInitiatedPostNavigation) { +TEST_F(NavigationCallbacksTest, RendererInitiatedPostNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; responses[url] = "<form method='post' id='form'></form>"; @@ -484,19 +519,23 @@ // Perform new page navigation. NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Submit the form using JavaScript. EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyPostStartedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyPostFinishedContext(web_state(), url, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteJavaScript(@"window.document.getElementById('form').submit();"); } // Tests successful reload of a page returned for post request. -TEST_F(StartAndFinishNavigationTest, ReloadPostNavigation) { +TEST_F(NavigationCallbacksTest, ReloadPostNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; const GURL action = HttpServer::MakeUrl("http://action.test"); @@ -508,12 +547,16 @@ // Perform new page navigation. NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Submit the form using JavaScript. EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteBlockAndWaitForLoad(action, ^{ ExecuteJavaScript(@"window.document.getElementById('form').submit();"); }); @@ -521,8 +564,10 @@ // Reload the page. EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyPostStartedContext(web_state(), action, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyPostFinishedContext(web_state(), action, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); // TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current // delegate does not run callback for ShowRepostFormWarningDialog. Clearing // the delegate will allow form resubmission. Remove this workaround (clearing @@ -535,7 +580,7 @@ } // Tests going forward to a page rendered from post response. -TEST_F(StartAndFinishNavigationTest, ForwardPostNavigation) { +TEST_F(NavigationCallbacksTest, ForwardPostNavigation) { const GURL url = HttpServer::MakeUrl("http://chromium.test"); std::map<GURL, std::string> responses; const GURL action = HttpServer::MakeUrl("http://action.test"); @@ -547,19 +592,25 @@ // Perform new page navigation. NavigationContext* context = nullptr; EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); LoadUrl(url); // Submit the form using JavaScript. EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteBlockAndWaitForLoad(action, ^{ ExecuteJavaScript(@"window.document.getElementById('form').submit();"); }); // Go Back. EXPECT_CALL(*observer_, DidStartNavigation(_)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)); + EXPECT_CALL(*observer_, DidStopLoading()); ExecuteBlockAndWaitForLoad(url, ^{ navigation_manager()->GoBack(); }); @@ -567,8 +618,10 @@ // Go forward. EXPECT_CALL(*observer_, DidStartNavigation(_)) .WillOnce(VerifyPostStartedContext(web_state(), action, &context)); + EXPECT_CALL(*observer_, DidStartLoading()); EXPECT_CALL(*observer_, DidFinishNavigation(_)) .WillOnce(VerifyPostFinishedContext(web_state(), action, &context)); + EXPECT_CALL(*observer_, DidStopLoading()); // TODO(crbug.com/700958): ios/web ignores |check_for_repost| flag and current // delegate does not run callback for ShowRepostFormWarningDialog. Clearing // the delegate will allow form resubmission. Remove this workaround (clearing
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 051d2da..864dda6 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2039,6 +2039,7 @@ registerLoadRequestForURL:url referrer:self.currentNavItemReferrer transition:ui::PageTransition::PAGE_TRANSITION_RELOAD]; + [self didStartLoadingURL:url]; [self.nativeController reload]; _webStateImpl->OnNavigationFinished(navigationContext.get()); [self loadCompleteWithSuccess:YES forNavigation:nil]; @@ -2139,8 +2140,6 @@ if (_loadPhase != web::PAGE_LOADING) return; - DCHECK(_webView); - const GURL currentURL([self currentURL]); _loadPhase = web::PAGE_LOADED;
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc index d1d6f415..b6d082e 100644 --- a/ios/web/web_thread_impl.cc +++ b/ios/web/web_thread_impl.cc
@@ -330,6 +330,31 @@ } // static +bool WebThread::PostBlockingPoolTask(const tracked_objects::Location& from_here, + base::OnceClosure task) { + return g_globals.Get().blocking_pool->PostWorkerTask(from_here, + std::move(task)); +} + +// static +bool WebThread::PostBlockingPoolTaskAndReply( + const tracked_objects::Location& from_here, + base::OnceClosure task, + base::OnceClosure reply) { + return g_globals.Get().blocking_pool->PostTaskAndReply( + from_here, std::move(task), std::move(reply)); +} + +// static +bool WebThread::PostBlockingPoolSequencedTask( + const std::string& sequence_token_name, + const tracked_objects::Location& from_here, + base::OnceClosure task) { + return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask( + sequence_token_name, from_here, std::move(task)); +} + +// static base::SequencedWorkerPool* WebThread::GetBlockingPool() { return g_globals.Get().blocking_pool.get(); }
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc index 2f5ad1d..e2301e7 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -232,15 +232,6 @@ return true; } -void BidirectionalStreamQuicImpl::OnTrailingHeadersAvailable( - const SpdyHeaderBlock& headers, - size_t frame_len) { - headers_bytes_received_ += frame_len; - if (delegate_) - delegate_->OnTrailersReceived(headers); - // |this| can be destroyed after this point. -} - void BidirectionalStreamQuicImpl::OnClose() { DCHECK(stream_); @@ -308,10 +299,36 @@ headers_bytes_received_ += rv; negotiated_protocol_ = kProtoQUIC; connect_timing_ = session_->GetConnectTiming(); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::ReadTrailingHeaders, + weak_factory_.GetWeakPtr())); if (delegate_) delegate_->OnHeadersReceived(initial_headers_); } +void BidirectionalStreamQuicImpl::ReadTrailingHeaders() { + int rv = stream_->ReadTrailingHeaders( + &trailing_headers_, + base::Bind(&BidirectionalStreamQuicImpl::OnReadTrailingHeadersComplete, + weak_factory_.GetWeakPtr())); + + if (rv != ERR_IO_PENDING) + OnReadTrailingHeadersComplete(rv); +} + +void BidirectionalStreamQuicImpl::OnReadTrailingHeadersComplete(int rv) { + DCHECK_NE(ERR_IO_PENDING, rv); + if (rv < 0) { + NotifyError(rv); + return; + } + + headers_bytes_received_ += rv; + + if (delegate_) + delegate_->OnTrailersReceived(trailing_headers_); +} + void BidirectionalStreamQuicImpl::OnReadDataComplete(int rv) { DCHECK_GE(rv, 0); read_buffer_ = nullptr;
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h index 28a0f319..3b25309 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.h +++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -58,14 +58,14 @@ private: // QuicChromiumClientStream::Delegate implementation: - void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) override; void OnClose() override; void OnError(int error) override; void OnStreamReady(int rv); void OnSendDataComplete(int rv); void OnReadInitialHeadersComplete(int rv); + void ReadTrailingHeaders(); + void OnReadTrailingHeadersComplete(int rv); void OnReadDataComplete(int rv); // Notifies the delegate of an error. @@ -92,6 +92,7 @@ LoadTimingInfo::ConnectTiming connect_timing_; SpdyHeaderBlock initial_headers_; + SpdyHeaderBlock trailing_headers_; // User provided read buffer for ReadData() response. scoped_refptr<IOBuffer> read_buffer_;
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index f02458b..9eaa5452 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -317,9 +317,12 @@ void OnTrailersReceived(const SpdyHeaderBlock& trailers) override { DCHECK_NE(ON_HEADERS_RECEIVED, phase_); DCHECK_NE(ON_DATA_READ, phase_); + // Make a copy of |response_headers| before the stream is deleted, since + // the headers are owned by the stream. + SpdyHeaderBlock trailers_copy = trailers.Clone(); if (phase_ == ON_TRAILERS_RECEIVED) DeleteStream(); - TestDelegateBase::OnTrailersReceived(trailers); + TestDelegateBase::OnTrailersReceived(trailers_copy); } void OnFailed(int error) override { @@ -367,7 +370,7 @@ kDefaultServerHostName, Perspective::IS_CLIENT), server_maker_(GetParam(), - connection_id_, + GetPeerInMemoryConnectionId(connection_id_), &clock_, kDefaultServerHostName, Perspective::IS_SERVER),
diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc index a084fe5c..0014b40 100644 --- a/net/quic/chromium/quic_chromium_client_stream.cc +++ b/net/quic/chromium/quic_chromium_client_stream.cc
@@ -54,10 +54,15 @@ ResetAndReturn(&read_headers_callback_).Run(rv); } -void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable( - const SpdyHeaderBlock& headers, - size_t frame_len) { - delegate_->OnTrailingHeadersAvailable(headers, frame_len); +void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable() { + if (!read_headers_callback_) + return; // Wait for ReadInitialHeaders to be called. + + int rv = ERR_QUIC_PROTOCOL_ERROR; + if (!stream_->DeliverTrailingHeaders(read_headers_buffer_, &rv)) + rv = ERR_QUIC_PROTOCOL_ERROR; + + ResetAndReturn(&read_headers_callback_).Run(rv); } void QuicChromiumClientStream::Handle::OnDataAvailable() { @@ -134,6 +139,21 @@ return ERR_IO_PENDING; } +int QuicChromiumClientStream::Handle::ReadTrailingHeaders( + SpdyHeaderBlock* header_block, + const CompletionCallback& callback) { + if (!stream_) + return ERR_CONNECTION_CLOSED; + + int frame_len = 0; + if (stream_->DeliverTrailingHeaders(header_block, &frame_len)) + return frame_len; + + read_headers_buffer_ = header_block; + read_headers_callback_ = callback; + return ERR_IO_PENDING; +} + size_t QuicChromiumClientStream::Handle::WriteHeaders( SpdyHeaderBlock header_block, bool fin, @@ -312,6 +332,7 @@ session_(session), can_migrate_(true), initial_headers_frame_len_(0), + trailing_headers_frame_len_(0), weak_factory_(this) {} QuicChromiumClientStream::~QuicChromiumClientStream() { @@ -352,8 +373,11 @@ size_t frame_len, const QuicHeaderList& header_list) { QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list); - NotifyHandleOfTrailingHeadersAvailableLater(received_trailers().Clone(), - frame_len); + trailing_headers_frame_len_ = frame_len; + if (handle_) { + // The handle will be notified of the headers via a posted task. + NotifyHandleOfTrailingHeadersAvailableLater(); + } } void QuicChromiumClientStream::OnPromiseHeaderList( @@ -514,33 +538,23 @@ handle_->OnInitialHeadersAvailable(); } -void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater( - SpdyHeaderBlock headers, - size_t frame_len) { +void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater() { DCHECK(handle_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind( &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable, - weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), - frame_len)); + weak_factory_.GetWeakPtr())); } -void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable( - SpdyHeaderBlock headers, - size_t frame_len) { +void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable() { if (!handle_) return; DCHECK(headers_delivered_); - // Only mark trailers consumed when we are about to notify delegate. - MarkTrailersConsumed(); // Post an async task to notify delegate of the FIN flag. NotifyHandleOfDataAvailableLater(); - net_log_.AddEvent( - NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS, - base::Bind(&SpdyHeaderBlockNetLogCallback, &headers)); - handle_->OnTrailingHeadersAvailable(headers, frame_len); + handle_->OnTrailingHeadersAvailable(); } bool QuicChromiumClientStream::DeliverInitialHeaders(SpdyHeaderBlock* headers, @@ -558,6 +572,22 @@ return true; } +bool QuicChromiumClientStream::DeliverTrailingHeaders(SpdyHeaderBlock* headers, + int* frame_len) { + if (received_trailers().empty()) + return false; + + net_log_.AddEvent( + NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS, + base::Bind(&SpdyHeaderBlockNetLogCallback, &received_trailers())); + + *headers = received_trailers().Clone(); + *frame_len = trailing_headers_frame_len_; + + MarkTrailersConsumed(); + return true; +} + void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() { DCHECK(handle_); base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/net/quic/chromium/quic_chromium_client_stream.h b/net/quic/chromium/quic_chromium_client_stream.h index e512b457..e95d4784 100644 --- a/net/quic/chromium/quic_chromium_client_stream.h +++ b/net/quic/chromium/quic_chromium_client_stream.h
@@ -39,10 +39,6 @@ public: Delegate() {} - // Called when trailing headers are available. - virtual void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) = 0; - // Called when the stream is closed by the peer. virtual void OnClose() = 0; @@ -82,6 +78,15 @@ int buffer_len, const CompletionCallback& callback); + // Reads trailing headers into |header_block| and returns the length of + // the HEADERS frame which contained them. If headers are not available, + // returns ERR_IO_PENDING and will invoke |callback| asynchronously when + // the headers arrive. + // TODO(rch): Invoke |callback| when there is a stream or connection error + // instead of calling OnClose() or OnError(). + int ReadTrailingHeaders(SpdyHeaderBlock* header_block, + const CompletionCallback& callback); + // Writes |header_block| to the peer. Closes the write side if |fin| is // true. If non-null, |ack_notifier_delegate| will be notified when the // headers are ACK'd by the peer. @@ -154,8 +159,7 @@ // Methods invoked by the stream. void OnInitialHeadersAvailable(); - void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len); + void OnTrailingHeadersAvailable(); void OnDataAvailable(); void OnCanWrite(); void OnClose(); @@ -260,16 +264,16 @@ bool DeliverInitialHeaders(SpdyHeaderBlock* header_block, int* frame_len); + bool DeliverTrailingHeaders(SpdyHeaderBlock* header_block, int* frame_len); + using QuicSpdyStream::HasBufferedData; using QuicStream::sequencer; private: void NotifyHandleOfInitialHeadersAvailableLater(); void NotifyHandleOfInitialHeadersAvailable(); - void NotifyHandleOfTrailingHeadersAvailableLater(SpdyHeaderBlock headers, - size_t frame_len); - void NotifyHandleOfTrailingHeadersAvailable(SpdyHeaderBlock headers, - size_t frame_len); + void NotifyHandleOfTrailingHeadersAvailableLater(); + void NotifyHandleOfTrailingHeadersAvailable(); void NotifyHandleOfDataAvailableLater(); void NotifyHandleOfDataAvailable(); @@ -291,6 +295,9 @@ // Length of the HEADERS frame containing initial headers. size_t initial_headers_frame_len_; + // Length of the HEADERS frame containing trailing headers. + size_t trailing_headers_frame_len_; + base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_; DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientStream);
diff --git a/net/quic/chromium/quic_chromium_client_stream_test.cc b/net/quic/chromium/quic_chromium_client_stream_test.cc index 0623610f..bb20cb3 100644 --- a/net/quic/chromium/quic_chromium_client_stream_test.cc +++ b/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -44,13 +44,6 @@ MOCK_METHOD0(OnSendData, int()); MOCK_METHOD2(OnSendDataComplete, int(int, bool*)); - void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) override { - trailers_ = headers.Clone(); - OnTrailingHeadersAvailableMock(headers, frame_len); - } - MOCK_METHOD2(OnTrailingHeadersAvailableMock, - void(const SpdyHeaderBlock& headers, size_t frame_len)); MOCK_METHOD0(OnClose, void()); MOCK_METHOD1(OnError, void(int)); MOCK_METHOD0(HasSendHeadersComplete, bool()); @@ -503,12 +496,11 @@ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data)); auto t = ProcessTrailers(trailers); - base::RunLoop run_loop; - EXPECT_CALL(delegate_, - OnTrailingHeadersAvailableMock(_, t.uncompressed_header_bytes())) - .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - run_loop.Run(); + TestCompletionCallback trailers_callback; + EXPECT_EQ(static_cast<int>(t.uncompressed_header_bytes()), + handle_->ReadTrailingHeaders(&delegate_.trailers_, + trailers_callback.callback())); // Read the body and verify that it arrives correctly. EXPECT_EQ(0, @@ -550,13 +542,9 @@ QuicHeaderList t = ProcessTrailers(trailers); EXPECT_FALSE(stream_->IsDoneReading()); - base::RunLoop run_loop2; - EXPECT_CALL(delegate_, - OnTrailingHeadersAvailableMock(_, t.uncompressed_header_bytes())) - .WillOnce( - testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); })); - - run_loop2.Run(); + EXPECT_EQ( + static_cast<int>(t.uncompressed_header_bytes()), + handle_->ReadTrailingHeaders(&delegate_.trailers_, callback.callback())); // Read the body and verify that it arrives correctly. EXPECT_EQ(0, callback.WaitForResult()); @@ -607,13 +595,10 @@ // Trailers are not delivered EXPECT_FALSE(stream_->IsDoneReading()); - base::RunLoop run_loop2; - EXPECT_CALL(delegate_, - OnTrailingHeadersAvailableMock(_, t.uncompressed_header_bytes())) - .WillOnce( - testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); })); - - run_loop2.Run(); + TestCompletionCallback callback2; + EXPECT_EQ( + static_cast<int>(t.uncompressed_header_bytes()), + handle_->ReadTrailingHeaders(&delegate_.trailers_, callback2.callback())); // Read the body and verify that it arrives correctly. // OnDataAvailable() should follow right after and Read() will return 0.
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc index a299a2612..c2caf5c 100644 --- a/net/quic/chromium/quic_http_stream.cc +++ b/net/quic/chromium/quic_http_stream.cc
@@ -56,6 +56,7 @@ has_response_status_(false), response_status_(ERR_UNEXPECTED), response_headers_received_(false), + trailing_headers_received_(false), headers_bytes_received_(0), headers_bytes_sent_(0), closed_stream_received_bytes_(0), @@ -464,10 +465,23 @@ } } -void QuicHttpStream::OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) { +void QuicHttpStream::ReadTrailingHeaders() { + if (!stream_) + return; + + int rv = stream_->ReadTrailingHeaders( + &trailing_header_block_, + base::Bind(&QuicHttpStream::OnReadTrailingHeadersComplete, + weak_factory_.GetWeakPtr())); + + if (rv != ERR_IO_PENDING) + OnReadTrailingHeadersComplete(rv); +} + +void QuicHttpStream::OnReadTrailingHeadersComplete(int rv) { DCHECK(response_headers_received_); - headers_bytes_received_ += frame_len; + if (rv > 0) + headers_bytes_received_ += rv; // QuicHttpStream ignores trailers. if (stream_->IsDoneReading()) { @@ -751,6 +765,11 @@ // Populate |connect_timing_| when response headers are received. This should // take care of 0-RTT where request is sent before handshake is confirmed. connect_timing_ = quic_session()->GetConnectTiming(); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&QuicHttpStream::ReadTrailingHeaders, + weak_factory_.GetWeakPtr())); + return OK; }
diff --git a/net/quic/chromium/quic_http_stream.h b/net/quic/chromium/quic_http_stream.h index be8833c4..562a076 100644 --- a/net/quic/chromium/quic_http_stream.h +++ b/net/quic/chromium/quic_http_stream.h
@@ -69,8 +69,6 @@ void SetPriority(RequestPriority priority) override; // QuicChromiumClientStream::Delegate implementation - void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) override; void OnClose() override; void OnError(int error) override; @@ -123,6 +121,8 @@ void OnReadResponseHeadersComplete(int rv); int ProcessResponseHeaders(const SpdyHeaderBlock& headers); + void ReadTrailingHeaders(); + void OnReadTrailingHeadersComplete(int rv); void OnReadBodyComplete(int rv); int HandleReadComplete(int rv); @@ -184,6 +184,9 @@ SpdyHeaderBlock response_header_block_; bool response_headers_received_; + SpdyHeaderBlock trailing_header_block_; + bool trailing_headers_received_; + // Number of bytes received by the headers stream on behalf of this stream. int64_t headers_bytes_received_; // Number of bytes sent by the headers stream on behalf of this stream.
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc index 9901f4c..8a9ba22 100644 --- a/net/quic/chromium/quic_http_stream_test.cc +++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -97,21 +97,6 @@ } }; -// Subclass of QuicHttpStream that closes itself when the first piece of data -// is received. -class AutoClosingStream : public QuicHttpStream { - public: - explicit AutoClosingStream( - std::unique_ptr<QuicChromiumClientSession::Handle> session) - : QuicHttpStream(std::move(session)) {} - - void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, - size_t frame_len) override { - Close(false); - } - -}; - // UploadDataStream that always returns errors on data read. class ReadErrorUploadDataStream : public UploadDataStream { public: @@ -197,8 +182,7 @@ }; QuicHttpStreamTest() - : use_closing_stream_(false), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), read_buffer_(new IOBufferWithSize(4096)), promise_id_(GetNthServerInitiatedStreamId(0)), stream_id_(GetNthClientInitiatedStreamId(0)), @@ -209,7 +193,7 @@ kDefaultServerHostName, Perspective::IS_CLIENT), server_maker_(GetParam(), - connection_id_, + GetPeerInMemoryConnectionId(connection_id_), &clock_, kDefaultServerHostName, Perspective::IS_SERVER), @@ -326,13 +310,8 @@ TestCompletionCallback callback; session_->CryptoConnect(callback.callback()); - stream_.reset(use_closing_stream_ - ? new AutoClosingStream(session_->CreateHandle()) - : new QuicHttpStream(session_->CreateHandle())); - - promised_stream_.reset(use_closing_stream_ - ? new AutoClosingStream(session_->CreateHandle()) - : new QuicHttpStream(session_->CreateHandle())); + stream_.reset(new QuicHttpStream(session_->CreateHandle())); + promised_stream_.reset(new QuicHttpStream(session_->CreateHandle())); push_promise_[":path"] = "/bar"; push_promise_[":authority"] = "www.example.org"; @@ -557,7 +536,6 @@ } BoundTestNetLog net_log_; - bool use_closing_stream_; MockSendAlgorithm* send_algorithm_; scoped_refptr<TestTaskRunner> runner_; std::unique_ptr<MockWrite[]> mock_writes_; @@ -1010,7 +988,6 @@ DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); AddWrite(ConstructAckAndRstStreamPacket(3)); - use_closing_stream_ = true; Initialize(); request_.method = "GET"; @@ -1051,7 +1028,6 @@ 1, GetNthClientInitiatedStreamId(0), kIncludeVersion, kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); - use_closing_stream_ = true; Initialize(); request_.method = "GET"; @@ -1405,7 +1381,6 @@ DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); AddWrite(ConstructAckAndRstStreamPacket(3)); - use_closing_stream_ = true; Initialize(); request_.method = "GET"; @@ -1451,7 +1426,6 @@ AddWrite(InnerConstructRequestHeadersPacket( 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, kFin, MEDIUM, &spdy_request_headers_frame_length, &header_stream_offset)); - use_closing_stream_ = true; Initialize(); request_.method = "GET"; @@ -1498,7 +1472,6 @@ // Regression test for http://crbug.com/294870 TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) { SetRequest("GET", "/", MEDIUM); - use_closing_stream_ = true; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); AddWrite(ConstructClientRstStreamPacket(2));
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 03af2f62..56c7420 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -162,7 +162,7 @@ // written in big endian. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_big_endian_connection_id_server, - false) + true) // Simplify QUIC\'s adaptive time loss detection to measure the necessary // reordering window for every spurious retransmit.
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc index 9a69d92..64feb881 100644 --- a/net/quic/core/quic_framer_test.cc +++ b/net/quic/core/quic_framer_test.cc
@@ -4844,9 +4844,9 @@ // clang-format on unsigned char* packets[] = {packet, packet_cid_be, packet39, packet_cid_be39}; - size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + size_t index = GetPacketIndex(framer_.version(), framer_.perspective()); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr);
diff --git a/net/traffic_annotation/network_traffic_annotation.h b/net/traffic_annotation/network_traffic_annotation.h index 98d9d4c..69c6206 100644 --- a/net/traffic_annotation/network_traffic_annotation.h +++ b/net/traffic_annotation/network_traffic_annotation.h
@@ -25,7 +25,7 @@ // Entry point to function that computes hash as constant expression. #define COMPUTE_STRING_HASH(S) \ - static_cast<int32_t>(recursive_hash<sizeof(S)>(S)) + static_cast<int32_t>(recursive_hash<sizeof(S) - 1>(S)) } // namespace @@ -118,7 +118,9 @@ DCHECK(partial_annotation.completing_id_hash_code == COMPUTE_STRING_HASH(unique_id) || partial_annotation.unique_id_hash_code == - COMPUTE_STRING_HASH("test_partial")); + COMPUTE_STRING_HASH("test_partial") || + partial_annotation.unique_id_hash_code == + COMPUTE_STRING_HASH("undefined")); #endif return NetworkTrafficAnnotationTag({partial_annotation.unique_id_hash_code}); } @@ -137,7 +139,9 @@ DCHECK(partial_annotation.completing_id_hash_code == COMPUTE_STRING_HASH(unique_id) || partial_annotation.unique_id_hash_code == - COMPUTE_STRING_HASH("test_partial")); + COMPUTE_STRING_HASH("test_partial") || + partial_annotation.unique_id_hash_code == + COMPUTE_STRING_HASH("undefined")); #endif return NetworkTrafficAnnotationTag({COMPUTE_STRING_HASH(unique_id)}); } @@ -196,6 +200,10 @@ #define NO_TRAFFIC_ANNOTATION_YET \ net::DefineNetworkTrafficAnnotation("undefined", "Nothing here yet.") +#define NO_PARTIAL_TRAFFIC_ANNOTATION_YET \ + net::DefinePartialNetworkTrafficAnnotation("undefined", "undefined", \ + "Nothing here yet.") + #define MISSING_TRAFFIC_ANNOTATION \ net::DefineNetworkTrafficAnnotation( \ "missing", "Function called without traffic annotation.")
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc index c5a17a5..9b9e10a4 100644 --- a/storage/browser/quota/client_usage_tracker.cc +++ b/storage/browser/quota/client_usage_tracker.cc
@@ -76,6 +76,7 @@ } ClientUsageTracker::~ClientUsageTracker() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (special_storage_policy_.get()) special_storage_policy_->RemoveObserver(this); } @@ -423,7 +424,7 @@ void ClientUsageTracker::OnGranted(const GURL& origin, int change_flags) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { int64_t usage = 0; if (GetCachedOriginUsage(origin, &usage)) { @@ -440,7 +441,7 @@ void ClientUsageTracker::OnRevoked(const GURL& origin, int change_flags) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { int64_t usage = 0; if (GetCachedOriginUsage(origin, &usage)) { @@ -456,7 +457,7 @@ } void ClientUsageTracker::OnCleared() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); global_limited_usage_ += global_unlimited_usage_; global_unlimited_usage_ = 0;
diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h index 2fbe765..1a5f6df 100644 --- a/storage/browser/quota/client_usage_tracker.h +++ b/storage/browser/quota/client_usage_tracker.h
@@ -15,7 +15,7 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "storage/browser/quota/quota_callbacks.h" #include "storage/browser/quota/quota_client.h" #include "storage/browser/quota/quota_task.h" @@ -32,7 +32,6 @@ // This class holds per-client usage tracking information and caches per-host // usage data. An instance of this class is created per client. class ClientUsageTracker : public SpecialStoragePolicy::Observer, - public base::NonThreadSafe, public base::SupportsWeakPtr<ClientUsageTracker> { public: typedef base::Callback<void(int64_t limited_usage, int64_t unlimited_usage)> @@ -132,6 +131,8 @@ scoped_refptr<SpecialStoragePolicy> special_storage_policy_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(ClientUsageTracker); };
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.cc b/storage/browser/quota/quota_temporary_storage_evictor.cc index b7af58c7..4eb97885 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.cc +++ b/storage/browser/quota/quota_temporary_storage_evictor.cc
@@ -56,6 +56,7 @@ } QuotaTemporaryStorageEvictor::~QuotaTemporaryStorageEvictor() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } void QuotaTemporaryStorageEvictor::GetStatistics( @@ -135,7 +136,7 @@ } void QuotaTemporaryStorageEvictor::Start() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::AutoReset<bool> auto_reset(&timer_disabled_for_testing_, false); StartEvictionTimerWithDelay(0); @@ -228,7 +229,7 @@ } void QuotaTemporaryStorageEvictor::OnGotEvictionOrigin(const GURL& origin) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (origin.is_empty()) { StartEvictionTimerWithDelay(interval_ms_); @@ -246,7 +247,7 @@ void QuotaTemporaryStorageEvictor::OnEvictionComplete( QuotaStatusCode status) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is // ok. No need to deal with the case that all of the Delete operations fail
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h index 187d3396..42d3e14 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.h +++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "base/timer/timer.h" #include "storage/browser/storage_browser_export.h" #include "storage/common/quota/quota_types.h" @@ -29,7 +29,7 @@ class QuotaEvictionHandler; struct QuotaSettings; -class STORAGE_EXPORT QuotaTemporaryStorageEvictor : public base::NonThreadSafe { +class STORAGE_EXPORT QuotaTemporaryStorageEvictor { public: struct Statistics { Statistics() @@ -110,6 +110,9 @@ base::OneShotTimer eviction_timer_; base::RepeatingTimer histogram_timer_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<QuotaTemporaryStorageEvictor> weak_factory_; DISALLOW_COPY_AND_ASSIGN(QuotaTemporaryStorageEvictor);
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 91eebb6..374817d5 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -25,9 +25,6 @@ # Untriaged but known real leaks. # ----------------------------------------------------------------- -crbug.com/327574 permissionclient/image-permissions.html [ Leak ] -crbug.com/327574 fast/loader/data-images-with-images-disabled.html [ Leak ] - # ----------------------------------------------------------------- # Untriaged but known leaks which may be false positives. # ----------------------------------------------------------------- @@ -51,15 +48,6 @@ crbug.com/661182 fast/loader/open-in-srcdoc-unload.html [ Leak ] # ----------------------------------------------------------------- -# Untriaged but known leaks of ActiveDOMObject (IndexedDB). -# ----------------------------------------------------------------- -# The leak detector's result for ActiveDOMObject (especially IndexedDB) is -# flaky and we need to fix the leak detector (crbug.com/507224). Until then, -# the tests for IndexedDB are skipped. -crbug.com/506752 external/wpt/IndexedDB/ [ Skip ] -crbug.com/506752 storage/indexeddb/ [ Skip ] - -# ----------------------------------------------------------------- # Untriaged but known leaks of ActiveDOMObject (http). # ----------------------------------------------------------------- crbug.com/506754 http/tests/inspector/service-workers/service-worker-agents.html [ Crash Leak ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/http-to-https-redirect-and-register.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/http-to-https-redirect-and-register.https.html new file mode 100644 index 0000000..d78b23a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/http-to-https-redirect-and-register.https.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<title>register on a secure page after redirect from an non-secure url</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<body> +<script> +'use strict'; + +// Loads a non-secure url in a new window, which redirects to |target_url|. +// That page then registers a service worker, and messages back with the result. +// Returns a promise that resolves with the result. +function redirect_and_register(target_url) { + var redirect_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() + + 'resources/redirect.py?Redirect='; + var child = window.open(redirect_url + encodeURIComponent(target_url)); + return new Promise(resolve => { + window.addEventListener('message', e => resolve(e.data)); + }) + .then(function(result) { + child.close(); + return result; + }); +} + +promise_test(function(t) { + var target_url = window.location.origin + base_path() + + 'resources/http-to-https-redirect-and-register-iframe.html'; + + return redirect_and_register(target_url) + .then(result => { + assert_equals(result, 'OK'); + }); + }, 'register on a secure page after redirect from an non-secure url'); + +promise_test(function(t) { + var target_url = get_host_info()['UNAUTHENTICATED_ORIGIN'] + base_path() + + 'resources/http-to-https-redirect-and-register-iframe.html'; + + return redirect_and_register(target_url) + .then(result => { + assert_equals(result, 'FAIL: SecurityError'); + }); + }, 'register on a non-secure page after redirect from an non-secure url'); +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/http-to-https-redirect-and-register-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/http-to-https-redirect-and-register-iframe.html new file mode 100644 index 0000000..8c48a18 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/http-to-https-redirect-and-register-iframe.html
@@ -0,0 +1,21 @@ +<!doctype html> +<title>register, unregister, and report result to opener</title> +<body> +<script> +'use strict'; + +navigator.serviceWorker.register('empty-worker.js', {scope: 'scope-register'}) + .then( + registration => { + registration.unregister().then(() => { + window.opener.postMessage('OK', '*'); + }); + }, + error => { + window.opener.postMessage('FAIL: ' + error.name, '*'); + }) + .catch(error => { + window.opener.postMessage('ERROR: ' + error.name, '*'); + }); +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/idl-callback-function-unittest.html b/third_party/WebKit/LayoutTests/fast/dom/idl-callback-function-unittest.html index 70e928c..53a0b6c 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/idl-callback-function-unittest.html +++ b/third_party/WebKit/LayoutTests/fast/dom/idl-callback-function-unittest.html
@@ -44,6 +44,13 @@ }, 'Callback function which takes a number sequence'); test(function() { + var callback = function(enum_value) { + assert_equals(enum_value, 'foo'); + }; + callbackFunctionTest.testEnumCallback(callback, 'foo'); +}, 'Callback function which takes an enum value'); + +test(function() { assert_throws(new TypeError(), function() { callbackFunctionTest.testCallback(null, 'hello', 'world'); });
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-basics.html deleted file mode 100644 index 8662ab30..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-basics.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<title>Credential Manager: CredentialsContainer basics.</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="resources/interfaces.js"></script> -<script> -test(function () { - assert_equals(typeof CredentialsContainer, "function"); - verify_interface('CredentialsContainer', navigator.credentials, { - 'get': 'function' - }); -}, 'Interfaces and attributes of CredentialsContainer'); -</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-basics.html index a27e317..4ce4423 100644 --- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-basics.html +++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-basics.html
@@ -2,7 +2,6 @@ <title>Credential Manager: get() basics.</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> -<script src="resources/interfaces.js"></script> <script> function stubResolverUndefinedChecker(c) { assert_equals(c, undefined); @@ -130,12 +129,6 @@ var password = "pencil"; function stubResolverChecker(c) { - verify_interface('PasswordCredential', c, { - id: 'string', - name: 'string', - iconURL: 'string' - }); - assert_equals(c.id, id); assert_equals(c.name, name); assert_equals(c.iconURL, icon);
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/federatedcredential-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/federatedcredential-basics.html index a177159..6754999 100644 --- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/federatedcredential-basics.html +++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/federatedcredential-basics.html
@@ -2,7 +2,6 @@ <title>Credential Manager: FederatedCredential basics.</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> -<script src="resources/interfaces.js"></script> <script> test(function() { var credential = new FederatedCredential({ @@ -12,17 +11,6 @@ 'iconURL': 'https://example.test/icon.png' }); - assert_true(credential instanceof Credential); - assert_true(credential instanceof FederatedCredential); - - verify_interface('FederatedCredential', credential, { - id: 'string', - name: 'string', - iconURL: 'string', - provider: 'string', - type: 'string' - }); - assert_equals(credential.id, 'id'); assert_equals(credential.name, 'name'); assert_equals(credential.iconURL, 'https://example.test/icon.png');
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/passwordcredential-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/passwordcredential-basics.html index ed5ba18..a01a049c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/passwordcredential-basics.html +++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/passwordcredential-basics.html
@@ -2,7 +2,6 @@ <title>Credential Manager: PasswordCredential basics.</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> -<script src="resources/interfaces.js"></script> <script> test(function() { var credential = new PasswordCredential({ @@ -12,13 +11,6 @@ iconURL: 'https://example.com/icon.png' }); - verify_interface('PasswordCredential', credential, { - id: 'string', - name: 'string', - iconURL: 'string', - type: 'string' - }); - assert_equals(credential.id, 'id'); assert_equals(credential.name, 'name'); assert_equals(credential.iconURL, 'https://example.com/icon.png');
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/interfaces.js b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/interfaces.js deleted file mode 100644 index eb00df65..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/resources/interfaces.js +++ /dev/null
@@ -1,15 +0,0 @@ -function verify_interface(name, instance, attributes) { - assert_true(name in self, - name + ' should be an defined type'); - if (instance) { - assert_true(instance instanceof self[name], - instance + ' should be an instance of ' + name); - Object.keys(attributes || {}).forEach(function(attribute) { - var type = attributes[attribute]; - assert_true(attribute in instance, - attribute + ' should be an attribute of ' + name); - assert_equals(typeof instance[attribute], type, - attribute + ' should be of type ' + type); - }); - } -}
diff --git a/third_party/WebKit/LayoutTests/http/tests/multipart/stop-loading.html b/third_party/WebKit/LayoutTests/http/tests/multipart/stop-loading.html index 6235b35..2c0e766 100644 --- a/third_party/WebKit/LayoutTests/http/tests/multipart/stop-loading.html +++ b/third_party/WebKit/LayoutTests/http/tests/multipart/stop-loading.html
@@ -12,6 +12,12 @@ assert_true(internals.isLoading(url), "The image should be loading before window.stop()."); } window.stop(); + + // We emulate window load event to signal testharness.js that we don't + // have to wait for window load event (that will never occur because + // we've called window.stop()) before test completes. + dispatchEvent(new Event('load')); + window.setTimeout(t.step_func(function() { if (window.internals) { assert_false(internals.isLoading(url), "The image should not be loading after window.stop().");
diff --git a/third_party/WebKit/LayoutTests/http/tests/resources/srcset-helper.js b/third_party/WebKit/LayoutTests/http/tests/resources/srcset-helper.js index 90b869a..3e5bc9fb 100644 --- a/third_party/WebKit/LayoutTests/http/tests/resources/srcset-helper.js +++ b/third_party/WebKit/LayoutTests/http/tests/resources/srcset-helper.js
@@ -21,11 +21,17 @@ } else { // Right now there is a bug that srcset does not properly deal with dynamic changes to the scale factor, // so to work around that, we must reload the page to get the new image. - sessionStorage.pageReloaded = true; - if (window.internals) { - internals.evictAllResources(); - } - document.location.reload(true); + // + // At the time of the Document load event, there might be other + // ongoing tasks that can cause new images to be loaded. To evict + // those images, we delay evictAllResources() call a little. + setTimeout(function() { + sessionStorage.pageReloaded = true; + if (window.internals) { + internals.evictAllResources(); + } + document.location.reload(true); + }, 300); } }
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/http-to-https-redirect-and-register.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.http-to-https-redirect-and-register-iframe.html similarity index 78% rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/http-to-https-redirect-and-register.html rename to third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.http-to-https-redirect-and-register-iframe.html index af07905..209c819f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/http-to-https-redirect-and-register.html +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.http-to-https-redirect-and-register-iframe.html
@@ -1,4 +1,10 @@ <!DOCTYPE html> +<!-- This test's file name is prefixed with `chromium.` because while a roughly + equivalent version is available in the Web Platform Tests project, the + limitations of the WPT infrastructure precludes the use of iframes for this + purpose. This version should be maintained only insofar as the functionality + under test concerns iframe contexts specifically; otherwise, modifications + should be contributed to the shared version. --> <title>register on a secure page after redirect from an non-secure url</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> @@ -6,6 +12,7 @@ <script src="resources/test-helpers.js"></script> <body> <script> +'use strict'; // Loads a non-secure url in an iframe, which redirects to |target_url|. // That page then registers a service worker, and messages back with the result.
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/register.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/register.html index e8713dd70..e954067 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/register.html +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/register.html
@@ -1,8 +1,9 @@ <!doctype html> <title>register</title> -<script src="test-helpers.js"></script> <body> <script> +'use strict'; + navigator.serviceWorker.register('empty-worker.js', {scope: 'scope-register'}) .then( registration => {
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn index b723540..b965807 100644 --- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn +++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -258,6 +258,8 @@ generated_core_testing_callback_function_files = [ "$bindings_core_v8_output_dir/TestCallback.cpp", "$bindings_core_v8_output_dir/TestCallback.h", + "$bindings_core_v8_output_dir/TestEnumCallback.cpp", + "$bindings_core_v8_output_dir/TestEnumCallback.h", "$bindings_core_v8_output_dir/TestInterfaceCallback.cpp", "$bindings_core_v8_output_dir/TestInterfaceCallback.h", "$bindings_core_v8_output_dir/TestReceiverObjectCallback.cpp",
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py b/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py index 3e10528..3bdf0c3 100644 --- a/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py +++ b/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
@@ -83,11 +83,15 @@ def arguments_context(arguments, return_cpp_type): def argument_context(argument): + idl_type = argument.idl_type return { - 'argument_name': '%sArgument' % argument.name, - 'cpp_value_to_v8_value': argument.idl_type.cpp_value_to_v8_value( + 'cpp_value_to_v8_value': idl_type.cpp_value_to_v8_value( argument.name, isolate='script_state_->GetIsolate()', creation_context='script_state_->GetContext()->Global()'), + 'enum_type': idl_type.enum_type, + 'enum_values': idl_type.enum_values, + 'name': argument.name, + 'v8_name': 'v8_%s' % argument.name, } argument_declarations = [
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_callback_interface.py b/third_party/WebKit/Source/bindings/scripts/v8_callback_interface.py index 00b12a2..c034dd3 100644 --- a/third_party/WebKit/Source/bindings/scripts/v8_callback_interface.py +++ b/third_party/WebKit/Source/bindings/scripts/v8_callback_interface.py
@@ -64,7 +64,7 @@ # FIXME: remove this function by making callback types consistent # (always use usual v8_types.cpp_type) idl_type_name = idl_type.name - if idl_type_name == 'String': + if idl_type_name == 'String' or idl_type.is_enum: return 'const String&' if idl_type_name == 'void': return 'void'
diff --git a/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl index 263ac1b95..664bbf1 100644 --- a/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
@@ -1,4 +1,4 @@ -{% from 'utilities.cpp.tmpl' import v8_value_to_local_cpp_value %} +{% from 'utilities.cpp.tmpl' import declare_enum_validation_variable, v8_value_to_local_cpp_value %} {% filter format_blink_cpp_source_code %} {% include 'copyright_block.txt' %} @@ -35,14 +35,24 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + + {% for argument in arguments if argument.enum_values %} + {% set valid_enum_variables = 'valid_' + argument.name + '_values' %} + {{declare_enum_validation_variable(argument.enum_values, valid_enum_variables) | indent(2)}} + if (!IsValidEnum({{argument.name}}, {{valid_enum_variables}}, WTF_ARRAY_LENGTH({{valid_enum_variables}}), "{{argument.enum_type}}", exceptionState)) { + NOTREACHED(); + return false; + } + {% endfor %} + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -52,10 +62,10 @@ isolate); {% for argument in arguments %} - v8::Local<v8::Value> {{argument.argument_name}} = {{argument.cpp_value_to_v8_value}}; + v8::Local<v8::Value> {{argument.v8_name}} = {{argument.cpp_value_to_v8_value}}; {% endfor %} {% if arguments %} - v8::Local<v8::Value> argv[] = { {{arguments | join(', ', 'argument_name')}} }; + v8::Local<v8::Value> argv[] = { {{arguments | join(', ', 'v8_name')}} }; {% else %} {# Empty array initializers are illegal, and don\'t compile in MSVC. #} v8::Local<v8::Value> *argv = nullptr;
diff --git a/third_party/WebKit/Source/bindings/tests/idls/core/TestCallbackFunctions.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestCallbackFunctions.idl index 1dfc9b4..5bd02fd1 100644 --- a/third_party/WebKit/Source/bindings/tests/idls/core/TestCallbackFunctions.idl +++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestCallbackFunctions.idl
@@ -11,6 +11,7 @@ callback VoidCallbackFunctionDictionaryArg = void (TestDictionary arg); callback VoidCallbackFunctionTestInterfaceSequenceArg = void (sequence<TestInterface> arg); callback StringSequenceCallbackFunctionLongSequenceArg = sequence<DOMString> (sequence<long> arg); +callback VoidCallbackFunctionEnumArg = void (TestEnum arg); callback VoidCallbackFunctionTypedef = void (String arg); interface TestCallbackFunctions {
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp index 0654295b5..bf8a745 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,8 +64,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> optionalAnyArgArgument = optionalAnyArg.V8Value(); - v8::Local<v8::Value> argv[] = { optionalAnyArgArgument }; + v8::Local<v8::Value> v8_optionalAnyArg = optionalAnyArg.V8Value(); + v8::Local<v8::Value> argv[] = { v8_optionalAnyArg }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp b/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp index 946c9ca..74c5c27 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,9 +64,9 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> num1Argument = v8::Integer::New(script_state_->GetIsolate(), num1); - v8::Local<v8::Value> num2Argument = v8::Integer::New(script_state_->GetIsolate(), num2); - v8::Local<v8::Value> argv[] = { num1Argument, num2Argument }; + v8::Local<v8::Value> v8_num1 = v8::Integer::New(script_state_->GetIsolate(), num1); + v8::Local<v8::Value> v8_num2 = v8::Integer::New(script_state_->GetIsolate(), num2); + v8::Local<v8::Value> argv[] = { v8_num1, v8_num2 }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp index 26f2b93..44dd5301 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,8 +64,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> argArgument = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); - v8::Local<v8::Value> argv[] = { argArgument }; + v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); + v8::Local<v8::Value> argv[] = { v8_arg }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp index d03a9a7..6e41217e 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp
@@ -46,14 +46,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate();
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp index 10a812f0..3c8cfe2 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,8 +64,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> argArgument = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); - v8::Local<v8::Value> argv[] = { argArgument }; + v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); + v8::Local<v8::Value> argv[] = { v8_arg }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp new file mode 100644 index 0000000..f76c36c --- /dev/null +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp
@@ -0,0 +1,105 @@ +// 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. + +// This file has been auto-generated by code_generator_v8.py. +// DO NOT MODIFY! + +// This file has been generated from the Jinja2 template in +// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl + +// clang-format off + +#include "VoidCallbackFunctionEnumArg.h" + +#include "bindings/core/v8/ExceptionState.h" +#include "bindings/core/v8/IDLTypes.h" +#include "bindings/core/v8/NativeValueTraitsImpl.h" +#include "bindings/core/v8/ToV8ForCore.h" +#include "bindings/core/v8/V8BindingForCore.h" +#include "core/dom/ExecutionContext.h" +#include "platform/bindings/ScriptState.h" +#include "platform/wtf/Assertions.h" + +namespace blink { + +// static +VoidCallbackFunctionEnumArg* VoidCallbackFunctionEnumArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) { + if (IsUndefinedOrNull(callback)) + return nullptr; + return new VoidCallbackFunctionEnumArg(scriptState, v8::Local<v8::Function>::Cast(callback)); +} + +VoidCallbackFunctionEnumArg::VoidCallbackFunctionEnumArg(ScriptState* scriptState, v8::Local<v8::Function> callback) + : script_state_(scriptState), + callback_(scriptState->GetIsolate(), this, callback) { + DCHECK(!callback_.IsEmpty()); +} + +DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionEnumArg) { + visitor->TraceWrappers(callback_.Cast<v8::Value>()); +} + +bool VoidCallbackFunctionEnumArg::call(ScriptWrappable* scriptWrappable, const String& arg) { + if (callback_.IsEmpty()) + return false; + + if (!script_state_->ContextIsValid()) + return false; + + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + + const char* valid_arg_values[] = { + "", + "EnumValue1", + "EnumValue2", + "EnumValue3", + }; + if (!IsValidEnum(arg, valid_arg_values, WTF_ARRAY_LENGTH(valid_arg_values), "TestEnum", exceptionState)) { + NOTREACHED(); + return false; + } + + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); + DCHECK(context); + if (context->IsContextSuspended() || context->IsContextDestroyed()) + return false; + + ScriptState::Scope scope(script_state_.Get()); + v8::Isolate* isolate = script_state_->GetIsolate(); + + v8::Local<v8::Value> thisValue = ToV8( + scriptWrappable, + script_state_->GetContext()->Global(), + isolate); + + v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg); + v8::Local<v8::Value> argv[] = { v8_arg }; + v8::TryCatch exceptionCatcher(isolate); + exceptionCatcher.SetVerbose(true); + + v8::Local<v8::Value> v8ReturnValue; + if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate), + context, + thisValue, + 1, + argv, + isolate).ToLocal(&v8ReturnValue)) { + return false; + } + + return true; +} + +VoidCallbackFunctionEnumArg* NativeValueTraits<VoidCallbackFunctionEnumArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) { + VoidCallbackFunctionEnumArg* nativeValue = VoidCallbackFunctionEnumArg::Create(ScriptState::Current(isolate), value); + if (!nativeValue) { + exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue( + "VoidCallbackFunctionEnumArg")); + } + return nativeValue; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.h b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.h new file mode 100644 index 0000000..47cf5d8 --- /dev/null +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.h
@@ -0,0 +1,56 @@ +// 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. + +// This file has been auto-generated by code_generator_v8.py. +// DO NOT MODIFY! + +// This file has been generated from the Jinja2 template in +// third_party/WebKit/Source/bindings/templates/callback_function.h.tmpl + +// clang-format off + +#ifndef VoidCallbackFunctionEnumArg_h +#define VoidCallbackFunctionEnumArg_h + +#include "bindings/core/v8/NativeValueTraits.h" +#include "core/CoreExport.h" +#include "platform/bindings/ScriptWrappable.h" +#include "platform/bindings/TraceWrapperV8Reference.h" +#include "platform/heap/Handle.h" +#include "platform/wtf/text/WTFString.h" + +namespace blink { + +class ScriptState; + +class CORE_EXPORT VoidCallbackFunctionEnumArg final : public GarbageCollectedFinalized<VoidCallbackFunctionEnumArg>, public TraceWrapperBase { + public: + static VoidCallbackFunctionEnumArg* Create(ScriptState*, v8::Local<v8::Value> callback); + + ~VoidCallbackFunctionEnumArg() = default; + + DEFINE_INLINE_TRACE() {} + DECLARE_TRACE_WRAPPERS(); + + bool call(ScriptWrappable* scriptWrappable, const String& arg); + + v8::Local<v8::Function> v8Value(v8::Isolate* isolate) { + return callback_.NewLocal(isolate); + } + + private: + VoidCallbackFunctionEnumArg(ScriptState*, v8::Local<v8::Function>); + + RefPtr<ScriptState> script_state_; + TraceWrapperV8Reference<v8::Function> callback_; +}; + +template <> +struct NativeValueTraits<VoidCallbackFunctionEnumArg> : public NativeValueTraitsBase<VoidCallbackFunctionEnumArg> { + CORE_EXPORT static VoidCallbackFunctionEnumArg* NativeValue(v8::Isolate*, v8::Local<v8::Value>, ExceptionState&); +}; + +} // namespace blink + +#endif // VoidCallbackFunctionEnumArg_h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp index 6d583ef..599df36 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,8 +64,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> divElementArgument = ToV8(divElement, script_state_->GetContext()->Global(), script_state_->GetIsolate()); - v8::Local<v8::Value> argv[] = { divElementArgument }; + v8::Local<v8::Value> v8_divElement = ToV8(divElement, script_state_->GetContext()->Global(), script_state_->GetIsolate()); + v8::Local<v8::Value> argv[] = { v8_divElement }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp index 0982e844..88dddb93 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp
@@ -48,14 +48,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -64,8 +65,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> argArgument = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); - v8::Local<v8::Value> argv[] = { argArgument }; + v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate()); + v8::Local<v8::Value> argv[] = { v8_arg }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp index 4c688dc..5ed37e9 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp
@@ -47,14 +47,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate(); @@ -63,8 +64,8 @@ script_state_->GetContext()->Global(), isolate); - v8::Local<v8::Value> argArgument = V8String(script_state_->GetIsolate(), arg); - v8::Local<v8::Value> argv[] = { argArgument }; + v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg); + v8::Local<v8::Value> argv[] = { v8_arg }; v8::TryCatch exceptionCatcher(isolate); exceptionCatcher.SetVerbose(true);
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp index a9d5082..3c76983 100644 --- a/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp
@@ -46,14 +46,15 @@ if (!script_state_->ContextIsValid()) return false; + // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. + // crbug.com/653769 + DummyExceptionStateForTesting exceptionState; + ExecutionContext* context = ExecutionContext::From(script_state_.Get()); DCHECK(context); if (context->IsContextSuspended() || context->IsContextDestroyed()) return false; - // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK. - // crbug.com/653769 - DummyExceptionStateForTesting exceptionState; ScriptState::Scope scope(script_state_.Get()); v8::Isolate* isolate = script_state_->GetIsolate();
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 065dbf2..fd004e14 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -193,7 +193,6 @@ #include "core/loader/DocumentLoader.h" #include "core/loader/FrameFetchContext.h" #include "core/loader/FrameLoader.h" -#include "core/loader/ImageLoader.h" #include "core/loader/NavigationScheduler.h" #include "core/loader/PrerendererClient.h" #include "core/loader/appcache/ApplicationCacheHost.h" @@ -3044,11 +3043,6 @@ // onLoad event handler, as in Radar 3206524. DetachParser(); - if (GetFrame() && CanExecuteScripts(kNotAboutToExecuteScript)) { - ImageLoader::DispatchPendingLoadEvents(); - ImageLoader::DispatchPendingErrorEvents(); - } - // JS running below could remove the frame or destroy the LayoutView so we // call those two functions repeatedly and don't save them on the stack.
diff --git a/third_party/WebKit/Source/core/events/BUILD.gn b/third_party/WebKit/Source/core/events/BUILD.gn index a474c98..f8590dd 100644 --- a/third_party/WebKit/Source/core/events/BUILD.gn +++ b/third_party/WebKit/Source/core/events/BUILD.gn
@@ -45,7 +45,6 @@ "EventPath.cpp", "EventPath.h", "EventQueue.h", - "EventSender.h", "EventTarget.cpp", "EventTarget.h", "EventUtil.cpp",
diff --git a/third_party/WebKit/Source/core/events/EventSender.h b/third_party/WebKit/Source/core/events/EventSender.h deleted file mode 100644 index 74ce9fb..0000000 --- a/third_party/WebKit/Source/core/events/EventSender.h +++ /dev/null
@@ -1,120 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef EventSender_h -#define EventSender_h - -#include "platform/Timer.h" -#include "platform/heap/Handle.h" -#include "platform/wtf/Vector.h" -#include "platform/wtf/text/AtomicString.h" - -namespace blink { - -template <typename T> -class EventSender final : public GarbageCollectedFinalized<EventSender<T>> { - WTF_MAKE_NONCOPYABLE(EventSender); - - public: - static EventSender* Create(const AtomicString& event_type) { - return new EventSender(event_type); - } - - const AtomicString& EventType() const { return event_type_; } - void DispatchEventSoon(T*); - void CancelEvent(T*); - void DispatchPendingEvents(); - -#if DCHECK_IS_ON() - bool HasPendingEvents(T* sender) const { - return dispatch_soon_list_.Find(sender) != kNotFound || - dispatching_list_.Find(sender) != kNotFound; - } -#endif - - DEFINE_INLINE_TRACE() { - visitor->Trace(dispatch_soon_list_); - visitor->Trace(dispatching_list_); - } - - private: - explicit EventSender(const AtomicString& event_type); - - void TimerFired(TimerBase*) { DispatchPendingEvents(); } - - AtomicString event_type_; - Timer<EventSender<T>> timer_; - HeapVector<Member<T>> dispatch_soon_list_; - HeapVector<Member<T>> dispatching_list_; -}; - -template <typename T> -EventSender<T>::EventSender(const AtomicString& event_type) - : event_type_(event_type), timer_(this, &EventSender::TimerFired) {} - -template <typename T> -void EventSender<T>::DispatchEventSoon(T* sender) { - dispatch_soon_list_.push_back(sender); - if (!timer_.IsActive()) - timer_.StartOneShot(0, BLINK_FROM_HERE); -} - -template <typename T> -void EventSender<T>::CancelEvent(T* sender) { - // Remove instances of this sender from both lists. - // Use loops because we allow multiple instances to get into the lists. - for (auto& sender_in_list : dispatch_soon_list_) { - if (sender_in_list == sender) - sender_in_list = nullptr; - } - for (auto& sender_in_list : dispatching_list_) { - if (sender_in_list == sender) - sender_in_list = nullptr; - } -} - -template <typename T> -void EventSender<T>::DispatchPendingEvents() { - // Need to avoid re-entering this function; if new dispatches are - // scheduled before the parent finishes processing the list, they - // will set a timer and eventually be processed. - if (!dispatching_list_.IsEmpty()) - return; - - timer_.Stop(); - - dispatching_list_.swap(dispatch_soon_list_); - for (auto& sender_in_list : dispatching_list_) { - if (T* sender = sender_in_list) { - sender_in_list = nullptr; - sender->DispatchPendingEvent(this); - } - } - dispatching_list_.clear(); -} - -} // namespace blink - -#endif // EventSender_h
diff --git a/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl b/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl index 91d2e6c..29ff386 100644 --- a/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl
@@ -23,6 +23,7 @@ // TODO(yukishiino): HTMLEmbedElement should not have [OverrideBuiltins]. [ OverrideBuiltins, + ActiveScriptWrappable, ] interface HTMLEmbedElement : HTMLElement { [CEReactions, Reflect, URL] attribute DOMString src; [CEReactions, Reflect] attribute DOMString type;
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp index 8b3c224..a5ca2891 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -137,6 +137,10 @@ TextControlElement::Trace(visitor); } +bool HTMLInputElement::HasPendingActivity() const { + return ImageLoader() && ImageLoader()->HasPendingActivity(); +} + HTMLImageLoader& HTMLInputElement::EnsureImageLoader() { if (!image_loader_) image_loader_ = HTMLImageLoader::Create(this);
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.h b/third_party/WebKit/Source/core/html/HTMLInputElement.h index 0d29aa4..71982f3e 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.h +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.h
@@ -30,6 +30,7 @@ #include "core/html/TextControlElement.h" #include "core/html/forms/StepRange.h" #include "platform/FileChooser.h" +#include "platform/bindings/ActiveScriptWrappable.h" namespace blink { @@ -46,14 +47,19 @@ class RadioButtonGroupScope; struct DateTimeChooserParameters; -class CORE_EXPORT HTMLInputElement : public TextControlElement { +class CORE_EXPORT HTMLInputElement + : public TextControlElement, + public ActiveScriptWrappable<HTMLInputElement> { DEFINE_WRAPPERTYPEINFO(); + USING_GARBAGE_COLLECTED_MIXIN(HTMLInputElement); public: static HTMLInputElement* Create(Document&, bool created_by_parser); ~HTMLInputElement() override; DECLARE_VIRTUAL_TRACE(); + bool HasPendingActivity() const final; + DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitspeechchange); bool ShouldAutocomplete() const final;
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.idl b/third_party/WebKit/Source/core/html/HTMLInputElement.idl index 7a9c7bd8..6fb8460 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.idl
@@ -23,7 +23,9 @@ enum SelectionMode { "select", "start", "end", "preserve" }; -interface HTMLInputElement : HTMLElement { +[ + ActiveScriptWrappable, +] interface HTMLInputElement : HTMLElement { [CEReactions, Reflect] attribute DOMString accept; [CEReactions, Reflect] attribute DOMString alt; [CEReactions, Reflect] attribute DOMString autocomplete;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h index ef1bfae..d1e2bd2 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -289,7 +289,7 @@ void SourceWasAdded(HTMLSourceElement*); // ScriptWrappable functions. - bool HasPendingActivity() const final; + bool HasPendingActivity() const override; AudioSourceProviderClient* AudioSourceNode() { return audio_source_node_; } void SetAudioSourceNode(AudioSourceProviderClient*);
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.idl b/third_party/WebKit/Source/core/html/HTMLObjectElement.idl index cb88965..5fc43e31 100644 --- a/third_party/WebKit/Source/core/html/HTMLObjectElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.idl
@@ -23,6 +23,7 @@ // TODO(yukishiino): HTMLObjectElement should not have [OverrideBuiltins]. [ OverrideBuiltins, + ActiveScriptWrappable, ] interface HTMLObjectElement : HTMLElement { [CEReactions, Reflect, URL] attribute DOMString data; [CEReactions, Reflect] attribute DOMString type;
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp index ec63ec23..1e7a734 100644 --- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -96,6 +96,10 @@ HTMLFrameOwnerElement::Trace(visitor); } +bool HTMLPlugInElement::HasPendingActivity() const { + return image_loader_ && image_loader_->HasPendingActivity(); +} + void HTMLPlugInElement::SetPersistedPlugin(PluginView* plugin) { if (persisted_plugin_ == plugin) return;
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h index 7e44763..56fe7227 100644 --- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h +++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
@@ -26,6 +26,7 @@ #include "core/CoreExport.h" #include "core/html/HTMLFrameOwnerElement.h" +#include "platform/bindings/ActiveScriptWrappable.h" #include "platform/bindings/SharedPersistent.h" #include "v8/include/v8.h" @@ -41,11 +42,17 @@ kShouldNotPreferPlugInsForImages }; -class CORE_EXPORT HTMLPlugInElement : public HTMLFrameOwnerElement { +class CORE_EXPORT HTMLPlugInElement + : public HTMLFrameOwnerElement, + public ActiveScriptWrappable<HTMLPlugInElement> { + USING_GARBAGE_COLLECTED_MIXIN(HTMLPlugInElement); + public: ~HTMLPlugInElement() override; DECLARE_VIRTUAL_TRACE(); + bool HasPendingActivity() const final; + void SetFocused(bool, WebFocusType) override; void ResetInstance(); // TODO(dcheng): Consider removing this, since HTMLEmbedElementLegacyCall
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp index 9629e2d..580cbeb 100644 --- a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp
@@ -95,6 +95,11 @@ HTMLMediaElement::Trace(visitor); } +bool HTMLVideoElement::HasPendingActivity() const { + return HTMLMediaElement::HasPendingActivity() || + (image_loader_ && image_loader_->HasPendingActivity()); +} + Node::InsertionNotificationRequest HTMLVideoElement::InsertedInto( ContainerNode* insertion_point) { if (insertion_point->isConnected() && custom_controls_fullscreen_detector_)
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/HTMLVideoElement.h index f8dbebc..99fe901 100644 --- a/third_party/WebKit/Source/core/html/HTMLVideoElement.h +++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
@@ -54,6 +54,8 @@ static HTMLVideoElement* Create(Document&); DECLARE_VIRTUAL_TRACE(); + bool HasPendingActivity() const final; + enum class MediaRemotingStatus { kNotStarted, kStarted, kDisabled }; // Node override.
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.idl b/third_party/WebKit/Source/core/html/HTMLVideoElement.idl index be1a4345..a5defd8 100644 --- a/third_party/WebKit/Source/core/html/HTMLVideoElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.idl
@@ -25,7 +25,9 @@ // https://html.spec.whatwg.org/#the-video-element -interface HTMLVideoElement : HTMLMediaElement { +[ + ActiveScriptWrappable, +] interface HTMLVideoElement : HTMLMediaElement { [CEReactions, Reflect] attribute unsigned long width; [CEReactions, Reflect] attribute unsigned long height; readonly attribute unsigned long videoWidth;
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp index 06d88cebc..9662b1b3 100644 --- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp +++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -29,7 +29,6 @@ #include "core/dom/Element.h" #include "core/dom/IncrementLoadEventDelayCount.h" #include "core/events/Event.h" -#include "core/events/EventSender.h" #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" #include "core/frame/UseCounter.h" @@ -56,18 +55,6 @@ namespace blink { -static ImageEventSender& LoadEventSender() { - DEFINE_STATIC_LOCAL(ImageEventSender, sender, - (ImageEventSender::Create(EventTypeNames::load))); - return sender; -} - -static ImageEventSender& ErrorEventSender() { - DEFINE_STATIC_LOCAL(ImageEventSender, sender, - (ImageEventSender::Create(EventTypeNames::error))); - return sender; -} - static inline bool PageIsBeingDismissed(Document* document) { return document->PageDismissalEventBeingDispatched() != Document::kNoDismissal; @@ -156,12 +143,8 @@ ImageLoader::ImageLoader(Element* element) : element_(element), - deref_element_timer_(this, &ImageLoader::TimerFired), - has_pending_load_event_(false), - has_pending_error_event_(false), image_complete_(true), loading_image_document_(false), - element_is_protected_(false), suppress_error_events_(false) { RESOURCE_LOADING_DVLOG(1) << "new ImageLoader " << this; } @@ -171,8 +154,8 @@ void ImageLoader::Dispose() { RESOURCE_LOADING_DVLOG(1) << "~ImageLoader " << this - << "; has_pending_load_event_=" << has_pending_load_event_ - << ", has_pending_error_event_=" << has_pending_error_event_; + << "; has pending load event=" << pending_load_event_.IsActive() + << ", has pending error event=" << pending_error_event_.IsActive(); if (image_) { image_->RemoveObserver(this); @@ -190,20 +173,10 @@ void ImageLoader::SetImageForTest(ImageResourceContent* new_image) { DCHECK(new_image); SetImageWithoutConsideringPendingLoadEvent(new_image); - - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); } void ImageLoader::ClearImage() { SetImageWithoutConsideringPendingLoadEvent(nullptr); - - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); } void ImageLoader::SetImageForImageDocument(ImageResource* new_image_resource) { @@ -218,11 +191,6 @@ // loading is just started. // TODO(hiroshige): clean up the behavior of flags. https://crbug.com/719759 image_complete_ = true; - - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); } void ImageLoader::SetImageWithoutConsideringPendingLoadEvent( @@ -230,14 +198,10 @@ DCHECK(failed_load_url_.IsEmpty()); ImageResourceContent* old_image = image_.Get(); if (new_image != old_image) { - if (has_pending_load_event_) { - LoadEventSender().CancelEvent(this); - has_pending_load_event_ = false; - } - if (has_pending_error_event_) { - ErrorEventSender().CancelEvent(this); - has_pending_error_event_ = false; - } + if (pending_load_event_.IsActive()) + pending_load_event_.Cancel(); + if (pending_error_event_.IsActive()) + pending_error_event_.Cancel(); UpdateImageState(new_image); if (new_image) { new_image->AddObserver(this); @@ -274,13 +238,18 @@ inline void ImageLoader::DispatchErrorEvent() { // There can be cases where DispatchErrorEvent() is called when there is // already a scheduled error event for the previous load attempt. - // In such cases we cancel the previous event and then re-schedule a new - // error event here. crbug.com/722500 - if (has_pending_error_event_) - ErrorEventSender().CancelEvent(this); - - has_pending_error_event_ = true; - ErrorEventSender().DispatchEventSoon(this); + // In such cases we cancel the previous event (by overwriting + // |pending_error_event_|) and then re-schedule a new error event here. + // crbug.com/722500 + pending_error_event_ = + TaskRunnerHelper::Get(TaskType::kDOMManipulation, + &GetElement()->GetDocument()) + ->PostCancellableTask( + BLINK_FROM_HERE, + WTF::Bind(&ImageLoader::DispatchPendingErrorEvent, + WrapPersistent(this), + WTF::Passed(IncrementLoadEventDelayCount::Create( + GetElement()->GetDocument())))); } inline void ImageLoader::CrossSiteOrCSPViolationOccurred( @@ -382,10 +351,8 @@ element_->GetLayoutObject()->IsImage() && new_image == old_image) { ToLayoutImage(element_->GetLayoutObject())->IntrinsicSizeChanged(); } else { - if (has_pending_load_event_) { - LoadEventSender().CancelEvent(this); - has_pending_load_event_ = false; - } + if (pending_load_event_.IsActive()) + pending_load_event_.Cancel(); // Cancel error events that belong to the previous load, which is now // cancelled by changing the src attribute. If newImage is null and @@ -393,10 +360,8 @@ // posted by this load and we should not cancel the event. // FIXME: If both previous load and this one got blocked with an error, we // can receive one error event instead of two. - if (has_pending_error_event_ && new_image) { - ErrorEventSender().CancelEvent(this); - has_pending_error_event_ = false; - } + if (pending_error_event_.IsActive() && new_image) + pending_error_event_.Cancel(); UpdateImageState(new_image); @@ -414,11 +379,6 @@ if (LayoutImageResource* image_resource = GetLayoutImageResource()) image_resource->ResetAnimation(); - - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); } void ImageLoader::UpdateFromElement(UpdateFromElementBehavior update_behavior, @@ -536,7 +496,7 @@ void ImageLoader::ImageNotifyFinished(ImageResourceContent* resource) { RESOURCE_LOADING_DVLOG(1) << "ImageLoader::imageNotifyFinished " << this - << "; has_pending_load_event_=" << has_pending_load_event_; + << "; has pending load event=" << pending_load_event_.IsActive(); DCHECK(failed_load_url_.IsEmpty()); DCHECK_EQ(resource, image_.Get()); @@ -572,12 +532,13 @@ ->UpdateUseCounters(GetElement()->GetDocument()); } - if (loading_image_document_) + if (loading_image_document_) { + CHECK(!pending_load_event_.IsActive()); return; + } if (resource->ErrorOccurred()) { - LoadEventSender().CancelEvent(this); - has_pending_load_event_ = false; + pending_load_event_.Cancel(); if (resource->GetResourceError().IsAccessCheck()) { CrossSiteOrCSPViolationOccurred( @@ -589,15 +550,19 @@ // https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element:the-img-element-55 if (!suppress_error_events_) DispatchErrorEvent(); - - // Only consider updating the protection ref-count of the Element - // immediately before returning from this function as doing so might result - // in the destruction of this ImageLoader. - UpdatedHasPendingEvent(); return; } - has_pending_load_event_ = true; - LoadEventSender().DispatchEventSoon(this); + + CHECK(!pending_load_event_.IsActive()); + pending_load_event_ = + TaskRunnerHelper::Get(TaskType::kDOMManipulation, + &GetElement()->GetDocument()) + ->PostCancellableTask( + BLINK_FROM_HERE, + WTF::Bind(&ImageLoader::DispatchPendingLoadEvent, + WrapPersistent(this), + WTF::Passed(IncrementLoadEventDelayCount::Create( + GetElement()->GetDocument())))); } LayoutImageResource* ImageLoader::GetLayoutImageResource() { @@ -640,76 +605,33 @@ if (image_ && !image_complete_ && !loading_image_document_) return true; - if (has_pending_load_event_ || has_pending_error_event_) + if (pending_load_event_.IsActive() || pending_error_event_.IsActive()) return true; return false; } -void ImageLoader::UpdatedHasPendingEvent() { - // If an Element that does image loading is removed from the DOM the - // load/error event for the image is still observable. As long as the - // ImageLoader is actively loading, the Element itself needs to be ref'ed to - // keep it from being destroyed by DOM manipulation or garbage collection. If - // such an Element wishes for the load to stop when removed from the DOM it - // needs to stop the ImageLoader explicitly. - bool was_protected = element_is_protected_; - element_is_protected_ = HasPendingEvent(); - if (was_protected == element_is_protected_) - return; - - if (element_is_protected_) { - if (deref_element_timer_.IsActive()) - deref_element_timer_.Stop(); - else - keep_alive_ = element_; - } else { - DCHECK(!deref_element_timer_.IsActive()); - deref_element_timer_.StartOneShot(0, BLINK_FROM_HERE); - } -} - -void ImageLoader::TimerFired(TimerBase*) { - keep_alive_.Clear(); -} - -void ImageLoader::DispatchPendingEvent(ImageEventSender* event_sender) { - RESOURCE_LOADING_DVLOG(1) << "ImageLoader::dispatchPendingEvent " << this; - DCHECK(event_sender == &LoadEventSender() || - event_sender == &ErrorEventSender()); - const AtomicString& event_type = event_sender->EventType(); - if (event_type == EventTypeNames::load) - DispatchPendingLoadEvent(); - if (event_type == EventTypeNames::error) - DispatchPendingErrorEvent(); -} - -void ImageLoader::DispatchPendingLoadEvent() { - CHECK(has_pending_load_event_); +void ImageLoader::DispatchPendingLoadEvent( + std::unique_ptr<IncrementLoadEventDelayCount> count) { if (!image_) return; CHECK(image_complete_); - has_pending_load_event_ = false; if (GetElement()->GetDocument().GetFrame()) DispatchLoadEvent(); - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); + // Checks Document's load event synchronously here for performance. + // This is safe because DispatchPendingLoadEvent() is called asynchronously. + count->ClearAndCheckLoadEvent(); } -void ImageLoader::DispatchPendingErrorEvent() { - CHECK(has_pending_error_event_); - has_pending_error_event_ = false; - +void ImageLoader::DispatchPendingErrorEvent( + std::unique_ptr<IncrementLoadEventDelayCount> count) { if (GetElement()->GetDocument().GetFrame()) GetElement()->DispatchEvent(Event::Create(EventTypeNames::error)); - // Only consider updating the protection ref-count of the Element immediately - // before returning from this function as doing so might result in the - // destruction of this ImageLoader. - UpdatedHasPendingEvent(); + // Checks Document's load event synchronously here for performance. + // This is safe because DispatchPendingErrorEvent() is called asynchronously. + count->ClearAndCheckLoadEvent(); } bool ImageLoader::GetImageAnimationPolicy(ImageAnimationPolicy& policy) { @@ -720,14 +642,6 @@ return true; } -void ImageLoader::DispatchPendingLoadEvents() { - LoadEventSender().DispatchPendingEvents(); -} - -void ImageLoader::DispatchPendingErrorEvents() { - ErrorEventSender().DispatchPendingEvents(); -} - void ImageLoader::ElementDidMoveToNewDocument() { if (delay_until_do_update_from_element_) { delay_until_do_update_from_element_->DocumentChanged(
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.h b/third_party/WebKit/Source/core/loader/ImageLoader.h index 175b8c6d..074d287b 100644 --- a/third_party/WebKit/Source/core/loader/ImageLoader.h +++ b/third_party/WebKit/Source/core/loader/ImageLoader.h
@@ -25,6 +25,7 @@ #include <memory> #include "core/CoreExport.h" +#include "core/dom/TaskRunnerHelper.h" #include "core/loader/resource/ImageResource.h" #include "core/loader/resource/ImageResourceContent.h" #include "core/loader/resource/ImageResourceObserver.h" @@ -40,10 +41,6 @@ class ImageLoader; class LayoutImageResource; -template <typename T> -class EventSender; -using ImageEventSender = EventSender<ImageLoader>; - class CORE_EXPORT ImageLoader : public GarbageCollectedFinalized<ImageLoader>, public ImageResourceObserver { USING_PRE_FINALIZER(ImageLoader, Dispose); @@ -112,15 +109,10 @@ bool HasPendingActivity() const { return HasPendingEvent() || pending_task_; } - bool HasPendingError() const { return has_pending_error_event_; } + bool HasPendingError() const { return pending_error_event_.IsActive(); } bool HadError() const { return !failed_load_url_.IsEmpty(); } - void DispatchPendingEvent(ImageEventSender*); - - static void DispatchPendingLoadEvents(); - static void DispatchPendingErrorEvents(); - bool GetImageAnimationPolicy(ImageAnimationPolicy&) final; protected: @@ -140,10 +132,9 @@ virtual void NoImageResourceToLoad() {} bool HasPendingEvent() const; - void UpdatedHasPendingEvent(); - void DispatchPendingLoadEvent(); - void DispatchPendingErrorEvent(); + void DispatchPendingLoadEvent(std::unique_ptr<IncrementLoadEventDelayCount>); + void DispatchPendingErrorEvent(std::unique_ptr<IncrementLoadEventDelayCount>); LayoutImageResource* GetLayoutImageResource(); void UpdateLayoutObject(); @@ -160,8 +151,6 @@ void CrossSiteOrCSPViolationOccurred(AtomicString); void EnqueueImageLoadingMicroTask(UpdateFromElementBehavior, ReferrerPolicy); - void TimerFired(TimerBase*); - KURL ImageSourceToKURL(AtomicString) const; // Used to determine whether to immediately initiate the load or to schedule a @@ -178,12 +167,7 @@ Member<Element> element_; Member<ImageResourceContent> image_; Member<ImageResource> image_resource_for_image_document_; - // FIXME: Oilpan: We might be able to remove this Persistent hack when - // ImageResourceClient is traceable. - GC_PLUGIN_IGNORE("http://crbug.com/383741") - Persistent<Element> keep_alive_; - Timer<ImageLoader> deref_element_timer_; AtomicString failed_load_url_; WeakPtr<Task> pending_task_; // owned by Microtask std::unique_ptr<IncrementLoadEventDelayCount> @@ -206,14 +190,11 @@ std::unique_ptr<IncrementLoadEventDelayCount> delay_until_image_notify_finished_; - // Indicates whether there is a pending task for the load/error event on - // EventSender. Will be replaced when EventSender is removed crbug/624697. - bool has_pending_load_event_ : 1; - bool has_pending_error_event_ : 1; + TaskHandle pending_load_event_; + TaskHandle pending_error_event_; bool image_complete_ : 1; bool loading_image_document_ : 1; - bool element_is_protected_ : 1; bool suppress_error_events_ : 1; };
diff --git a/third_party/WebKit/Source/core/svg/SVGImageElement.h b/third_party/WebKit/Source/core/svg/SVGImageElement.h index 50af0db..18a375c 100644 --- a/third_party/WebKit/Source/core/svg/SVGImageElement.h +++ b/third_party/WebKit/Source/core/svg/SVGImageElement.h
@@ -27,13 +27,16 @@ #include "core/svg/SVGGraphicsElement.h" #include "core/svg/SVGImageLoader.h" #include "core/svg/SVGURIReference.h" +#include "platform/bindings/ActiveScriptWrappable.h" #include "platform/heap/Handle.h" namespace blink { -class CORE_EXPORT SVGImageElement final : public SVGGraphicsElement, - public ImageElementBase, - public SVGURIReference { +class CORE_EXPORT SVGImageElement final + : public SVGGraphicsElement, + public ImageElementBase, + public SVGURIReference, + public ActiveScriptWrappable<SVGImageElement> { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(SVGImageElement); @@ -51,6 +54,10 @@ return preserve_aspect_ratio_.Get(); } + bool HasPendingActivity() const final { + return GetImageLoader().HasPendingActivity(); + } + // Exposed for testing. ImageResourceContent* CachedImage() const { return GetImageLoader().GetImage();
diff --git a/third_party/WebKit/Source/core/svg/SVGImageElement.idl b/third_party/WebKit/Source/core/svg/SVGImageElement.idl index a402b8b..5402271 100644 --- a/third_party/WebKit/Source/core/svg/SVGImageElement.idl +++ b/third_party/WebKit/Source/core/svg/SVGImageElement.idl
@@ -25,7 +25,9 @@ // https://svgwg.org/svg2-draft/embedded.html#InterfaceSVGImageElement -interface SVGImageElement : SVGGraphicsElement { +[ + ActiveScriptWrappable, +] interface SVGImageElement : SVGGraphicsElement { [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedLength x; [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedLength y; [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedLength width;
diff --git a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp index 230ecdd1..8d9aeab 100644 --- a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp +++ b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
@@ -5,6 +5,7 @@ #include "core/testing/CallbackFunctionTest.h" #include "bindings/core/v8/TestCallback.h" +#include "bindings/core/v8/TestEnumCallback.h" #include "bindings/core/v8/TestInterfaceCallback.h" #include "bindings/core/v8/TestReceiverObjectCallback.h" #include "bindings/core/v8/TestSequenceCallback.h" @@ -67,4 +68,10 @@ return Vector<String>(); } +void CallbackFunctionTest::testEnumCallback(TestEnumCallback* callback, + const String& enum_value, + ExceptionState& exception_state) { + callback->call(nullptr, enum_value); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.h b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.h index fa403b2..bc222ae 100644 --- a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.h +++ b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.h
@@ -15,6 +15,7 @@ class ExceptionState; class HTMLDivElement; class TestCallback; +class TestEnumCallback; class TestInterfaceCallback; class TestReceiverObjectCallback; class TestSequenceCallback; @@ -44,6 +45,9 @@ Vector<String> testSequenceCallback(TestSequenceCallback*, const Vector<int>& numbers, ExceptionState&); + void testEnumCallback(TestEnumCallback*, + const String& enum_value, + ExceptionState&); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.idl b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.idl index a0ca345..bbbabb4 100644 --- a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.idl +++ b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.idl
@@ -6,6 +6,7 @@ callback TestInterfaceCallback = void (HTMLDivElement divElement); callback TestReceiverObjectCallback = void (); callback TestSequenceCallback = sequence<DOMString> (sequence<long> numbers); +callback TestEnumCallback = void (InternalEnum arg); interface CallbackFunctionTest { [RaisesException] DOMString testCallback(TestCallback callback, DOMString message1, DOMString message2); @@ -13,4 +14,5 @@ [RaisesException] void testInterfaceCallback(TestInterfaceCallback callback, HTMLDivElement divElement); [RaisesException] void testReceiverObjectCallback(TestReceiverObjectCallback callback); [RaisesException] sequence<DOMString> testSequenceCallback(TestSequenceCallback callback, sequence<long> numbers); + [RaisesException] void testEnumCallback(TestEnumCallback callback, InternalEnum enum_value); };
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java index 33f99ea..7d95743 100644 --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -18,6 +18,7 @@ import android.os.Build; import android.provider.MediaStore; import android.text.TextUtils; +import android.webkit.MimeTypeMap; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ContentUriUtils; @@ -191,6 +192,9 @@ * @param camera Intent for selecting files from camera. */ private void launchSelectFileWithCameraIntent(boolean hasCameraPermission, Intent camera) { + RecordHistogram.recordEnumeratedHistogram("Android.SelectFileDialogScope", + determineSelectFileDialogScope(), SELECT_FILE_DIALOG_SCOPE_COUNT); + Intent camcorder = null; if (mSupportsVideoCapture && hasCameraPermission) { camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); @@ -214,15 +218,19 @@ if (mWindowAndroid.showIntent(soundRecorder, this, R.string.low_memory_error)) return; } + // Use new photo picker, if available. + Activity activity = mWindowAndroid.getActivity().get(); + if (activity != null && usePhotoPicker(mFileTypes) + && UiUtils.showPhotoPicker(activity, this, mAllowMultiple)) { + return; + } + Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && mAllowMultiple) { getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); } - RecordHistogram.recordEnumeratedHistogram("Android.SelectFileDialogScope", - determineSelectFileDialogScope(), SELECT_FILE_DIALOG_SCOPE_COUNT); - ArrayList<Intent> extraIntents = new ArrayList<Intent>(); if (!noSpecificType()) { // Create a chooser based on the accept type that was specified in the webpage. Note @@ -252,12 +260,6 @@ if (soundRecorder != null) extraIntents.add(soundRecorder); } - // Use new photo picker, if available. - Activity activity = mWindowAndroid.getActivity().get(); - if (activity != null && UiUtils.showPhotoPicker(activity, this, mAllowMultiple)) { - return; - } - Intent chooser = new Intent(Intent.ACTION_CHOOSER); if (!extraIntents.isEmpty()) { chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, @@ -270,6 +272,41 @@ } } + /** + * Determines if a photo picker can be used instead of the stock Android picker. + * @return True if only images types are being requested. + */ + @VisibleForTesting + public static boolean usePhotoPicker(List<String> fileTypes) { + for (String type : fileTypes) { + String mimeType = ensureMimeType(type); + if (!mimeType.startsWith("image/")) return false; + } + return true; + } + + /** + * Convert |type| to MIME type (known types only). + * @param type The type to convert. Can be either a MIME type or an extension (should include + * the leading dot). If an extension is passed in, it is converted to the + * corresponding MIME type (via {@link MimeTypeMap}), or "application/octet-stream" + * if the MIME type is not known. + * @return The MIME type, if known, or "application/octet-stream" otherwise (or blank if input + * is blank). + */ + @VisibleForTesting + public static String ensureMimeType(String type) { + if (type.length() == 0) return ""; + + String extension = MimeTypeMap.getFileExtensionFromUrl(type); + if (extension.length() > 0) { + String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mimeType != null) return mimeType; + return "application/octet-stream"; + } + return type; + } + @Override public void onPickerUserAction(Action action, String[] photos) { UiUtils.dismissPhotoPicker();