diff --git a/.gn b/.gn index d3f9ffee..df8816d 100644 --- a/.gn +++ b/.gn
@@ -34,158 +34,7 @@ #"//chrome_elf/*", #"//cloud_print/*", - #"//components/*", # Needs nacl below. - "//components:*", - "//components/about_handler/*", - "//components/about_ui/*", - "//components/app_modal/*", - "//components/audio_modem/*", - "//components/autofill/*", - "//components/auto_login_parser/*", - "//components/bitmap_uploader/*", - "//components/bookmarks/*", - "//components/browser_sync/*", - "//components/browser_watcher/*", - "//components/browsing_data/*", - "//components/bubble/*", - "//components/captive_portal/*", - "//components/cdm/*", - "//components/certificate_reporting/*", - "//components/certificate_transparency/*", - "//components/chrome_apps/*", - "//components/clipboard/*", - "//components/cloud_devices/*", - "//components/component_updater/*", - "//components/compression/*", - "//components/constrained_window/*", - "//components/content_settings/*", - "//components/cookie_config/*", - "//components/copresence/*", - "//components/crash/*", - "//components/cronet/*", - "//components/crx_file/*", - "//components/data_reduction_proxy/*", - "//components/data_usage/*", - "//components/data_use_measurement/*", - "//components/device_event_log/*", - "//components/devtools_discovery/*", - "//components/devtools_http_handler/*", - "//components/devtools_service/*", - "//components/dom_distiller/*", - "//components/domain_reliability/*", - "//components/drive/*", - "//components/enhanced_bookmarks/*", - "//components/error_page/*", - "//components/exp/*", - "//components/external_video_surface/*", - "//components/favicon/*", - "//components/favicon_base/*", - "//components/feedback/*", - "//components/filesystem/*", - "//components/flags_ui/*", - "//components/font_service/*", - "//components/gcm_driver/*", - "//components/google/*", - "//components/gpu/*", - "//components/guest_view/*", - "//components/handoff/*", - "//components/history/*", - "//components/html_viewer/*", - "//components/infobars/*", - "//components/invalidation/*", - "//components/json_schema/*", - "//components/keyed_service/*", - "//components/language_usage_metrics/*", - "//components/leveldb_proto/*", - "//components/login/*", - "//components/memory_pressure/*", - "//components/message_port/*", - "//components/metrics/*", - "//components/metrics_services_manager/*", - "//components/mime_util/*", - "//components/mus/*", - "//components/nacl/*", - "//components/navigation_interception/*", - "//components/navigation_metrics/*", - "//components/net_log/*", - "//components/network_hints/*", - "//components/network_time/*", - "//components/offline_pages/*", - "//components/omnibox/*", - "//components/onc/*", - "//components/open_from_clipboard/*", - "//components/os_crypt/*", - "//components/ownership/*", - "//components/packed_ct_ev_whitelist/*", - "//components/page_load_metrics/*", - "//components/pairing/*", - "//components/password_manager/*", - "//components/pdf/*", - "//components/pdf_viewer/*", - "//components/plugins/*", - "//components/policy/*", - "//components/power/*", - "//components/precache/*", - "//components/pref_registry/*", - "//components/printing/*", - "//components/proximity_auth/*", - "//components/proxy_config/*", - "//components/query_parser/*", - "//components/rappor/*", - "//components/renderer_context_menu/*", - "//components/resource_provider/*", - "//components/resources/*", - "//components/rlz/*", - "//components/safe_browsing_db/*", - "//components/safe_json/*", - "//components/scheduler/*", - "//components/search/*", - "//components/search_engines/*", - "//components/search_provider_logos/*", - "//components/security_interstitials/*", - "//components/service_tab_launcher/*", - "//components/session_manager/*", - "//components/sessions/*", - "//components/signin/*", - "//components/ssl_config/*", - "//components/ssl_errors/*", - "//components/startup_metric_utils/*", - "//components/storage_monitor/*", - "//components/strings/*", - "//components/suggestions/*", - "//components/sync_bookmarks/*", - "//components/sync_driver/*", - "//components/sync_sessions/*", - "//components/syncable_prefs/*", - "//components/test/*", - "//components/test_runner/*", - "//components/timers/*", - "//components/toolbar/*", - "//components/tools/*", - "//components/tracing/*", - "//components/translate/*", - "//components/ui/*", - "//components/undo/*", - "//components/update_client/*", - "//components/upload_list/*", - "//components/url_formatter/*", - "//components/url_matcher/*", - "//components/user_manager/*", - "//components/user_prefs/*", - "//components/variations/*", - "//components/visitedlink/*", - "//components/wallpaper/*", - "//components/web_cache/*", - "//components/web_modal/*", - "//components/web_resource/*", - "//components/web_view/*", - "//components/webcrypto/*", - "//components/webdata/*", - "//components/webdata_services/*", - "//components/webp_transcode/*", - "//components/webui_generator/*", - "//components/webusb/*", - "//components/wifi/*", + "//components/*", #"//content/*", # A whole lot of errors. "//content/public/common:result_codes",
diff --git a/BUILD.gn b/BUILD.gn index 1637b803..f160eb2f0 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -560,7 +560,6 @@ "//chrome_elf:dll_hash_main", "//cloud_print:cloud_print_unittests", "//cloud_print/service/win:cloud_print_service", - "//components/crash/content/tools:crash_service", "//components/wifi:wifi_test", "//net:quic_client", "//net:quic_server", @@ -785,7 +784,7 @@ if (is_win) { deps += [ "//components/test_runner:layout_test_helper", - "//content/shell:crash_service", + "//content/shell:content_shell_crash_service", ] } @@ -844,14 +843,12 @@ if (is_win) { deps += [ - "//content/shell:crash_service", + "//chrome/tools/crash_service", # "//gpu:angle_perftests", TODO(GYP): crbug.com/537008 ] if (target_cpu == "x86") { - deps += [ - # "//content/shell:crash_service_win64", TODO(GYP): crbug.com/537009 - ] + deps += [ "//chrome/tools/crash_service:crash_service_win64" ] } } else { deps += [ "//breakpad:minidump_stackwalk($host_toolchain)" ]
diff --git a/DEPS b/DEPS index 18dea05..c20d763 100644 --- a/DEPS +++ b/DEPS
@@ -39,11 +39,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': '7d5105c4d2a9be7ef9ddba646471c35d4c966d97', + 'skia_revision': 'c60b310af7635204b8186c616ffdd190d8bf5fe1', # 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': 'ddbc27f642c6e5b2efce59f8cfddaee82597c6fd', + 'v8_revision': '35e626ccab705fb865846f109826361d230a8cd9', # 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. @@ -87,7 +87,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'a0559c4cc7e9f95b41982a8f4ba10a04173c6c75', + 'nacl_revision': '296d9ac73190fbd37f699461600e83b16ec0d2b3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling dEQP # and whatever else without interference from each other. @@ -178,7 +178,7 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '8673e8623e0739a507ce0f98d8b0be7311437ebd', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '43331afad7fbd83697c8482b999b13191cf8cfe2', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/WATCHLISTS b/WATCHLISTS index 77accd11..013e12f 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -246,7 +246,7 @@ 'chrome/browser/resources/chromeos/', }, 'clang_update': { - 'filepath': 'tools/clang/scripts/update.sh' + 'filepath': 'tools/clang/scripts/update.py' }, 'clipboard': { 'filepath': 'clipboard|dnd|drag|drop',
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index ca80b7e2..ebebc65 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2408,6 +2408,18 @@ } /** + * Returns true if the page is visible according to DOM page visibility API. + * See http://www.w3.org/TR/page-visibility/ + * This method is only called by tests and will return the supposed CVC + * visibility without waiting a pending mUpdateVisibilityRunnable to run. + */ + @VisibleForTesting + public boolean isPageVisible() { + if (isDestroyed(NO_WARN)) return mIsContentViewCoreVisible; + return nativeIsVisible(mNativeAwContents); + } + + /** * Key for opaque state in bundle. Note this is only public for tests. */ public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE";
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsRenderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsRenderTest.java index 0b17619..a1a6c07 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsRenderTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsRenderTest.java
@@ -120,10 +120,27 @@ final int width = mAwContents.getContentWidthCss(); final int height = mAwContents.getContentHeightCss(); visibleBitmap = GraphicsTestUtils.drawAwContentsOnUiThread(mAwContents, width, height); + + // Things that affect DOM page visibility: + // 1. isPaused + // 2. window's visibility, if the webview is attached to a window. + // Note android.view.View's visibility does not affect DOM page visibility. runTestOnUiThread(new Runnable() { @Override public void run() { mContainerView.setVisibility(View.INVISIBLE); + assertTrue(mAwContents.isPageVisible()); + + mAwContents.onPause(); + assertFalse(mAwContents.isPageVisible()); + + mAwContents.onResume(); + assertTrue(mAwContents.isPageVisible()); + + // Simulate a window visiblity change. WebView test app can't + // manipulate the window visibility directly. + mAwContents.onWindowVisibilityChanged(View.INVISIBLE); + assertFalse(mAwContents.isPageVisible()); } });
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc index f81014e8..755c10ef 100644 --- a/base/android/jni_array_unittest.cc +++ b/base/android/jni_array_unittest.cc
@@ -4,6 +4,10 @@ #include "base/android/jni_array.h" +#include <stdint.h> + +#include <limits> + #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "testing/gtest/include/gtest/gtest.h" @@ -57,7 +61,8 @@ } TEST(JniArray, IntConversions) { - const int kInts[] = { 0, 1, -1, kint32min, kint32max}; + const int kInts[] = {0, 1, -1, std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max()}; const size_t kLen = arraysize(kInts); JNIEnv* env = AttachCurrentThread(); @@ -258,7 +263,8 @@ ASSERT_TRUE(array.obj()); // Populate int[][] object. - const int kInts0[] = {0, 1, -1, kint32min, kint32max}; + const int kInts0[] = {0, 1, -1, std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max()}; const size_t kLen0 = arraysize(kInts0); ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0, kLen0); env->SetObjectArrayElement(array.obj(), 0, int_array0.obj());
diff --git a/base/basictypes.h b/base/basictypes.h index 7607735..2f440f7 100644 --- a/base/basictypes.h +++ b/base/basictypes.h
@@ -29,7 +29,6 @@ const uint8 kuint8max = 0xFF; const uint32 kuint32max = 0xFFFFFFFF; const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL; -const int32 kint32min = -0x7FFFFFFF - 1; const int32 kint32max = 0x7FFFFFFF; const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1; const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
diff --git a/base/location.h b/base/location.h index 477dc022..8f77f7e 100644 --- a/base/location.h +++ b/base/location.h
@@ -58,11 +58,7 @@ // it comes from __FILE__, so no need to check the contents of the string. // See the definition of FROM_HERE in location.h, and how it is used // elsewhere. - - // Due to inconsistent definitions of uint64_t and uintptr_t, casting the - // file name pointer to a uintptr_t causes a compiler error for some - // platforms. The solution is to explicitly cast it to a uint64_t. - return base::HashPair(reinterpret_cast<uint64_t>(location.file_name()), + return base::HashPair(reinterpret_cast<uintptr_t>(location.file_name()), location.line_number()); } };
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc index 63d60148..e51b214 100644 --- a/base/process/process_metrics_linux.cc +++ b/base/process/process_metrics_linux.cc
@@ -214,13 +214,14 @@ // First call, just set the last values. last_cpu_time_ = time; last_cpu_ = GetProcessCPU(process_); - return 0; + return 0.0; } - int64 time_delta = (time - last_cpu_time_).InMicroseconds(); - DCHECK_NE(time_delta, 0); - if (time_delta == 0) - return 0; + TimeDelta time_delta = time - last_cpu_time_; + if (time_delta.is_zero()) { + NOTREACHED(); + return 0.0; + } int cpu = GetProcessCPU(process_); @@ -229,8 +230,18 @@ // are together adding to more than one CPU's worth. TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu); TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_); - double percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() / - TimeDelta::FromMicroseconds(time_delta).InSecondsF(); + + // If the number of threads running in the process has decreased since the + // last time this function was called, |last_cpu_time| will be greater than + // |cpu_time| which will result in a negative value in the below percentage + // calculation. We prevent this by clamping to 0. crbug.com/546565. + // This computation is known to be shaky when threads are destroyed between + // "last" and "now", but for our current purposes, it's all right. + double percentage = 0.0; + if (last_cpu_time < cpu_time) { + percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() / + time_delta.InSecondsF(); + } last_cpu_time_ = time; last_cpu_ = cpu;
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc index 31479cef..b29ceb6 100644 --- a/base/process/process_metrics_unittest.cc +++ b/base/process/process_metrics_unittest.cc
@@ -7,6 +7,8 @@ #include <sstream> #include <string> +#include "base/bind.h" +#include "base/strings/string_number_conversions.h" #include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,6 +16,20 @@ namespace base { namespace debug { +#if defined(OS_LINUX) || defined(OS_CHROMEOS) +namespace { + +void BusyWork(std::vector<std::string>* vec) { + int64_t test_value = 0; + for (int i = 0; i < 100000; ++i) { + ++test_value; + vec->push_back(base::Int64ToString(test_value)); + } +} + +} // namespace +#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) + // Tests for SystemMetrics. // Exists as a class so it can be a friend of SystemMetrics. class SystemMetricsTest : public testing::Test { @@ -270,6 +286,51 @@ } #endif // defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + +// Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when +// the number of threads running on the process decreases between two successive +// calls to it. +TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { + base::ProcessHandle handle = base::GetCurrentProcessHandle(); + scoped_ptr<ProcessMetrics> metrics( + ProcessMetrics::CreateProcessMetrics(handle)); + + EXPECT_GE(metrics->GetCPUUsage(), 0.0); + Thread thread1("thread1"); + Thread thread2("thread2"); + Thread thread3("thread3"); + + thread1.StartAndWaitForTesting(); + thread2.StartAndWaitForTesting(); + thread3.StartAndWaitForTesting(); + + ASSERT_TRUE(thread1.IsRunning()); + ASSERT_TRUE(thread2.IsRunning()); + ASSERT_TRUE(thread3.IsRunning()); + + std::vector<std::string> vec1; + std::vector<std::string> vec2; + std::vector<std::string> vec3; + + thread1.task_runner()->PostTask(FROM_HERE, base::Bind(&BusyWork, &vec1)); + thread2.task_runner()->PostTask(FROM_HERE, base::Bind(&BusyWork, &vec2)); + thread3.task_runner()->PostTask(FROM_HERE, base::Bind(&BusyWork, &vec3)); + + EXPECT_GE(metrics->GetCPUUsage(), 0.0); + + thread1.Stop(); + EXPECT_GE(metrics->GetCPUUsage(), 0.0); + + thread2.Stop(); + EXPECT_GE(metrics->GetCPUUsage(), 0.0); + + thread3.Stop(); + EXPECT_GE(metrics->GetCPUUsage(), 0.0); +} + +#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) + #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \ defined(OS_LINUX) || defined(OS_ANDROID) TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc index f0eda25a..d721cbf 100644 --- a/base/sequence_checker_unittest.cc +++ b/base/sequence_checker_unittest.cc
@@ -66,7 +66,6 @@ void TearDown() override { other_thread_.Stop(); - pool()->Shutdown(); } protected: @@ -309,7 +308,6 @@ base::Bind(&SequenceCheckedObject::DoStuff, base::Unretained(sequence_checked_object.get()))); second_pool_owner.pool()->FlushForTesting(); - second_pool_owner.pool()->Shutdown(); } #if ENABLE_SEQUENCE_CHECKER
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc index b1a1a89c..dd13c4a2 100644 --- a/base/test/launcher/test_launcher.cc +++ b/base/test/launcher/test_launcher.cc
@@ -468,10 +468,7 @@ parallel_jobs_(parallel_jobs) { } -TestLauncher::~TestLauncher() { - if (worker_pool_owner_) - worker_pool_owner_->pool()->Shutdown(); -} +TestLauncher::~TestLauncher() {} bool TestLauncher::Run() { if (!Init())
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc index b0d8b7a..37bad2b2 100644 --- a/base/test/sequenced_worker_pool_owner.cc +++ b/base/test/sequenced_worker_pool_owner.cc
@@ -18,8 +18,11 @@ has_work_call_count_(0) {} SequencedWorkerPoolOwner::~SequencedWorkerPoolOwner() { + pool_->Shutdown(); pool_ = NULL; - MessageLoop::current()->Run(); + + // Spin the current message loop until SWP destruction verified in OnDestruct. + exit_loop_.Run(); } const scoped_refptr<SequencedWorkerPool>& SequencedWorkerPoolOwner::pool() { @@ -51,8 +54,7 @@ } void SequencedWorkerPoolOwner::OnDestruct() { - constructor_message_loop_->task_runner()->PostTask( - FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure()); + constructor_message_loop_->PostTask(FROM_HERE, exit_loop_.QuitClosure()); } } // namespace base
diff --git a/base/test/sequenced_worker_pool_owner.h b/base/test/sequenced_worker_pool_owner.h index bf5f2f7..20bffb1 100644 --- a/base/test/sequenced_worker_pool_owner.h +++ b/base/test/sequenced_worker_pool_owner.h
@@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" +#include "base/run_loop.h" #include "base/synchronization/lock.h" #include "base/threading/sequenced_worker_pool.h" @@ -25,6 +26,9 @@ // strange races with other tests that touch global stuff (like histograms and // logging). However, this requires that nothing else on this thread holds a // ref to the pool when the SequencedWorkerPoolOwner is destroyed. +// +// This class calls Shutdown on the owned SequencedWorkerPool in the destructor. +// Tests may themselves call Shutdown earlier to test shutdown behavior. class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver { public: SequencedWorkerPoolOwner(size_t max_threads, @@ -46,7 +50,11 @@ void WillWaitForShutdown() override; void OnDestruct() override; + // Used to run the current thread's message loop until the + // SequencedWorkerPool's destruction has been verified. + base::RunLoop exit_loop_; MessageLoop* const constructor_message_loop_; + scoped_refptr<SequencedWorkerPool> pool_; Closure will_wait_for_shutdown_callback_;
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc index 1080262..bd380efb 100644 --- a/base/threading/sequenced_task_runner_handle_unittest.cc +++ b/base/threading/sequenced_task_runner_handle_unittest.cc
@@ -61,7 +61,6 @@ base::Bind(&SequencedTaskRunnerHandleTest::GetTaskRunner, base::Bind(&WaitableEvent::Signal, base::Unretained(&event)))); event.Wait(); - owner.pool()->Shutdown(); } class ThreadRunner : public DelegateSimpleThread::Delegate {
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc index 5812ee7..262c4fb 100644 --- a/base/threading/sequenced_worker_pool_unittest.cc +++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -234,8 +234,6 @@ ResetPool(); } - void TearDown() override { pool()->Shutdown(); } - const scoped_refptr<SequencedWorkerPool>& pool() { return pool_owner_->pool(); } @@ -351,7 +349,6 @@ ASSERT_EQ(1u, completion_sequence.size()); ASSERT_EQ(1, completion_sequence[0]); - pool()->Shutdown(); // Shutdown is asynchronous, so use ResetPool() to block until the pool is // fully destroyed (and thus shut down). ResetPool(); @@ -430,9 +427,6 @@ std::vector<int> result = tracker()->WaitUntilTasksComplete(2*kNumTasks); EXPECT_EQ(2 * kNumTasks, result.size()); - - pool2.pool()->Shutdown(); - pool1.pool()->Shutdown(); } // Test that tasks with the same sequence token are executed in order but don't @@ -799,33 +793,30 @@ SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken(); SequencedWorkerPool::SequenceToken unsequenced_token; - scoped_refptr<SequencedWorkerPool> unused_pool = - new SequencedWorkerPool(2, "unused_pool"); + SequencedWorkerPoolOwner unused_pool_owner(2, "unused_pool"); EXPECT_FALSE(pool()->RunsTasksOnCurrentThread()); EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token1)); EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token2)); EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(unsequenced_token)); - EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread()); - EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token1)); - EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token2)); + EXPECT_FALSE(unused_pool_owner.pool()->RunsTasksOnCurrentThread()); EXPECT_FALSE( - unused_pool->IsRunningSequenceOnCurrentThread(unsequenced_token)); + unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread(token1)); + EXPECT_FALSE( + unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread(token2)); + EXPECT_FALSE(unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread( + unsequenced_token)); pool()->PostSequencedWorkerTask( - token1, FROM_HERE, - base::Bind(&IsRunningOnCurrentThreadTask, - token1, token2, pool(), unused_pool)); + token1, FROM_HERE, base::Bind(&IsRunningOnCurrentThreadTask, token1, + token2, pool(), unused_pool_owner.pool())); pool()->PostSequencedWorkerTask( token2, FROM_HERE, - base::Bind(&IsRunningOnCurrentThreadTask, - token2, unsequenced_token, pool(), unused_pool)); + base::Bind(&IsRunningOnCurrentThreadTask, token2, unsequenced_token, + pool(), unused_pool_owner.pool())); pool()->PostWorkerTask( - FROM_HERE, - base::Bind(&IsRunningOnCurrentThreadTask, - unsequenced_token, token1, pool(), unused_pool)); - pool()->Shutdown(); - unused_pool->Shutdown(); + FROM_HERE, base::Bind(&IsRunningOnCurrentThreadTask, unsequenced_token, + token1, pool(), unused_pool_owner.pool())); } // Checks that tasks are destroyed in the right context during shutdown. If a @@ -947,16 +938,14 @@ pool()->FlushForTesting(); } -TEST(SequencedWorkerPoolRefPtrTest, ShutsDownCleanWithContinueOnShutdown) { - MessageLoop loop; - scoped_refptr<SequencedWorkerPool> pool(new SequencedWorkerPool(3, "Pool")); +TEST_F(SequencedWorkerPoolTest, ShutsDownCleanWithContinueOnShutdown) { scoped_refptr<SequencedTaskRunner> task_runner = - pool->GetSequencedTaskRunnerWithShutdownBehavior( - pool->GetSequenceToken(), + pool()->GetSequencedTaskRunnerWithShutdownBehavior( + pool()->GetSequenceToken(), base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); // Upon test exit, should shut down without hanging. - pool->Shutdown(); + pool()->Shutdown(); } class SequencedWorkerPoolTaskRunnerTestDelegate {
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn index 1495b20..edde7b61 100644 --- a/blimp/client/BUILD.gn +++ b/blimp/client/BUILD.gn
@@ -22,6 +22,8 @@ "compositor/render_widget_message_processor.h", "compositor/test/dummy_layer_driver.cc", "compositor/test/dummy_layer_driver.h", + "navigation_message_processor.cc", + "navigation_message_processor.h", ] defines = [ "BLIMP_CLIENT_IMPLEMENTATION=1" ] @@ -47,6 +49,7 @@ sources = [ "compositor/render_widget_message_processor_unittest.cc", + "navigation_message_processor_unittest.cc", ] deps = [ @@ -56,7 +59,9 @@ "//base/test:test_support", "//blimp/common/proto", "//blimp/net:blimp_net", + "//blimp/net:test_support", "//cc/proto", + "//skia", "//testing/gmock", "//testing/gtest", ] @@ -196,6 +201,7 @@ ":blimp_client", ":jni_headers", "//base", + "//blimp/net:blimp_net", "//skia", "//ui/gfx/geometry", "//ui/gl",
diff --git a/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java b/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java index ca82caa0..9de79ea6 100644 --- a/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java +++ b/blimp/client/android/java/src/org/chromium/blimp/toolbar/Toolbar.java
@@ -85,6 +85,14 @@ return nativeOnBackPressed(mNativeToolbarPtr); } + /** + * To be called when the user triggers a forward navigation action. + */ + public void onForwardPressed() { + if (mNativeToolbarPtr == 0) return; + nativeOnForwardPressed(mNativeToolbarPtr); + } + // View overrides. @Override protected void onFinishInflate() { @@ -124,14 +132,29 @@ // Methods that are called by native via JNI. @CalledByNative - private void onNavigationStateChanged(String url, Bitmap favicon, String title) { + private void onEngineSentUrl(String url) { if (url != null) mUrlBar.setText(url); - // TODO(dtrainor): Add a UI for favicon and title data and tie it in here. + } + + @CalledByNative + private void onEngineSentFavicon(Bitmap favicon) { + // TODO(dtrainor): Add a UI for the favicon. + } + + @CalledByNative + private void onEngineSentTitle(String title) { + // TODO(dtrainor): Add a UI for the title. + } + + @CalledByNative + private void onEngineSentLoading(boolean loading) { + // TODO(dtrainor): Add a UI for the loading state. } private native long nativeInit(); private native void nativeDestroy(long nativeToolbar); private native void nativeOnUrlTextEntered(long nativeToolbar, String text); private native void nativeOnReloadPressed(long nativeToolbar); + private native void nativeOnForwardPressed(long nativeToolbar); private native boolean nativeOnBackPressed(long nativeToolbar); }
diff --git a/blimp/client/android/toolbar.cc b/blimp/client/android/toolbar.cc index b15b9e2..27468e9b 100644 --- a/blimp/client/android/toolbar.cc +++ b/blimp/client/android/toolbar.cc
@@ -5,6 +5,8 @@ #include "blimp/client/android/toolbar.h" #include "base/android/jni_string.h" +#include "base/lazy_instance.h" +#include "blimp/net/null_blimp_message_processor.h" #include "jni/Toolbar_jni.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/android/java_bitmap.h" @@ -12,6 +14,15 @@ namespace blimp { +namespace { + +const int kDummyTabId = 0; + +base::LazyInstance<blimp::NullBlimpMessageProcessor> + g_null_message_processor = LAZY_INSTANCE_INITIALIZER; + +} // namespace + // static static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) { return reinterpret_cast<intptr_t>(new Toolbar(env, jobj)); @@ -23,54 +34,72 @@ } Toolbar::Toolbar(JNIEnv* env, - const base::android::JavaParamRef<jobject>& jobj) { + const base::android::JavaParamRef<jobject>& jobj) + : navigation_message_processor_(g_null_message_processor.Pointer()) { java_obj_.Reset(env, jobj); + + navigation_message_processor_.SetDelegate(kDummyTabId, this); } -Toolbar::~Toolbar() {} +Toolbar::~Toolbar() { + navigation_message_processor_.RemoveDelegate(kDummyTabId); +} void Toolbar::Destroy(JNIEnv* env, jobject jobj) { delete this; } void Toolbar::OnUrlTextEntered(JNIEnv* env, jobject jobj, jstring text) { - // TODO(dtrainor): Notify the content lite NavigationController. + navigation_message_processor_.NavigateToUrlText( + kDummyTabId, + base::android::ConvertJavaStringToUTF8(env, text)); } void Toolbar::OnReloadPressed(JNIEnv* env, jobject jobj) { - // TODO(dtrainor): Notify the content lite NavigationController. + navigation_message_processor_.Reload(kDummyTabId); +} + +void Toolbar::OnForwardPressed(JNIEnv* env, jobject jobj) { + navigation_message_processor_.GoForward(kDummyTabId); } jboolean Toolbar::OnBackPressed(JNIEnv* env, jobject jobj) { - // TODO(dtrainor): Notify the content lite NavigationController. + navigation_message_processor_.GoBack(kDummyTabId); + // TODO(dtrainor): Find a way to determine whether or not we're at the end of // our history stack. return true; } -void Toolbar::OnNavigationStateChanged(const GURL* url, - const SkBitmap* favicon, - const std::string* title) { +void Toolbar::OnUrlChanged(int tab_id, const GURL& url) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jstring> jurl( + base::android::ConvertUTF8ToJavaString(env, url.spec())); + + Java_Toolbar_onEngineSentUrl(env, java_obj_.obj(), jurl.obj()); +} + +void Toolbar::OnFaviconChanged(int tab_id, const SkBitmap& favicon) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jobject> jfavicon(gfx::ConvertToJavaBitmap(&favicon)); + + Java_Toolbar_onEngineSentFavicon(env, java_obj_.obj(), jfavicon.obj()); +} + +void Toolbar::OnTitleChanged(int tab_id, const std::string& title) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jstring> jtitle( + base::android::ConvertUTF8ToJavaString(env, title)); + + Java_Toolbar_onEngineSentTitle(env, java_obj_.obj(), jtitle.obj()); +} + +void Toolbar::OnLoadingChanged(int tab_id, bool loading) { JNIEnv* env = base::android::AttachCurrentThread(); - ScopedJavaLocalRef<jstring> jurl; - ScopedJavaLocalRef<jobject> jfavicon; - ScopedJavaLocalRef<jstring> jtitle; - - if (url) - jurl = base::android::ConvertUTF8ToJavaString(env, url->spec()); - - if (favicon) - jfavicon = gfx::ConvertToJavaBitmap(favicon); - - if (title) - jtitle = base::android::ConvertUTF8ToJavaString(env, *title); - - Java_Toolbar_onNavigationStateChanged(env, - java_obj_.obj(), - jurl.obj(), - jfavicon.obj(), - jtitle.obj()); + Java_Toolbar_onEngineSentLoading(env, + java_obj_.obj(), + static_cast<jboolean>(loading)); } } // namespace blimp
diff --git a/blimp/client/android/toolbar.h b/blimp/client/android/toolbar.h index 47f18ed..f9d210d 100644 --- a/blimp/client/android/toolbar.h +++ b/blimp/client/android/toolbar.h
@@ -7,6 +7,7 @@ #include "base/android/jni_android.h" #include "base/macros.h" +#include "blimp/client/navigation_message_processor.h" class GURL; class SkBitmap; @@ -16,7 +17,7 @@ // The native component of org.chromium.blimp.toolbar.Toolbar. This handles // marshalling calls between Java and native. Specifically, this passes calls // between Toolbar.java <=> content_lite's NavigationController layer. -class Toolbar { +class Toolbar : public NavigationMessageProcessor::NavigationMessageDelegate { public: static bool RegisterJni(JNIEnv* env); @@ -26,18 +27,20 @@ void Destroy(JNIEnv* env, jobject jobj); void OnUrlTextEntered(JNIEnv* env, jobject jobj, jstring text); void OnReloadPressed(JNIEnv* env, jobject jobj); + void OnForwardPressed(JNIEnv* env, jobject jobj); jboolean OnBackPressed(JNIEnv* env, jobject jobj); - // TODO(dtrainor): To be called by a the content lite NavigationController. - // Should probably be an overridden delegate method so the network code can be - // multi platform. - void OnNavigationStateChanged(const GURL* url, - const SkBitmap* favicon, - const std::string* title); + // NavigationMessageDelegate implementation. + void OnUrlChanged(int tab_id, const GURL& url) override; + void OnFaviconChanged(int tab_id, const SkBitmap& favicon) override; + void OnTitleChanged(int tab_id, const std::string& title) override; + void OnLoadingChanged(int tab_id, bool loading) override; private: virtual ~Toolbar(); + NavigationMessageProcessor navigation_message_processor_; + // Reference to the Java object which owns this class. base::android::ScopedJavaGlobalRef<jobject> java_obj_;
diff --git a/blimp/client/compositor/blimp_compositor.cc b/blimp/client/compositor/blimp_compositor.cc index 02f80f45..9c783dcc 100644 --- a/blimp/client/compositor/blimp_compositor.cc +++ b/blimp/client/compositor/blimp_compositor.cc
@@ -153,7 +153,8 @@ HandlePendingOutputSurfaceRequest(); } -void BlimpCompositor::DidInitializeOutputSurface() {} +void BlimpCompositor::DidInitializeOutputSurface() { +} void BlimpCompositor::DidFailToInitializeOutputSurface() {}
diff --git a/blimp/client/compositor/render_widget_message_processor_unittest.cc b/blimp/client/compositor/render_widget_message_processor_unittest.cc index 98d7d7b..b2aa921 100644 --- a/blimp/client/compositor/render_widget_message_processor_unittest.cc +++ b/blimp/client/compositor/render_widget_message_processor_unittest.cc
@@ -9,6 +9,7 @@ #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/common/proto/compositor.pb.h" #include "blimp/common/proto/render_widget.pb.h" +#include "blimp/net/test_common.h" #include "cc/proto/compositor_message.pb.h" #include "net/base/net_errors.h" #include "testing/gmock/include/gmock/gmock.h" @@ -23,24 +24,6 @@ namespace blimp { namespace { -class MockBlimpMessageProcessor : public BlimpMessageProcessor { - public: - MockBlimpMessageProcessor() {} - - ~MockBlimpMessageProcessor() override {} - - // Adapts calls from ProcessMessage to MockableProcessMessage by - // unboxing the |message| scoped_ptr for GMock compatibility. - void ProcessMessage(scoped_ptr<BlimpMessage> message, - const net::CompletionCallback& callback) { - MockableProcessMessage(*message); - if (!callback.is_null()) - callback.Run(net::OK); - } - - MOCK_METHOD1(MockableProcessMessage, - void(const BlimpMessage& message)); -}; class MockRenderWidgetMessageDelegate : public RenderWidgetMessageProcessor::RenderWidgetMessageDelegate { @@ -74,7 +57,7 @@ RenderWidgetMessage* details = message->mutable_render_widget(); details->set_type(RenderWidgetMessage::INITIALIZE); details->set_render_widget_id(rw_id); - processor->ProcessMessage(message.Pass(), + processor->ProcessMessage(std::move(message), net::CompletionCallback()); } @@ -87,7 +70,7 @@ CompositorMessage* details = message->mutable_compositor(); details->set_render_widget_id(rw_id); - processor->ProcessMessage(message.Pass(), + processor->ProcessMessage(std::move(message), net::CompletionCallback()); } @@ -130,17 +113,17 @@ SendRenderWidgetMessage(&processor_, 2, 1U); EXPECT_CALL(out_processor_, - MockableProcessMessage(CompMsgEquals(1, 2U))).Times(1); + MockableProcessMessage(CompMsgEquals(1, 2U), _)).Times(1); processor_.SendCompositorMessage(1, cc::proto::CompositorMessage()); SendRenderWidgetMessage(&processor_, 1, 3U); EXPECT_CALL(out_processor_, - MockableProcessMessage(CompMsgEquals(1, 3U))).Times(1); + MockableProcessMessage(CompMsgEquals(1, 3U), _)).Times(1); processor_.SendCompositorMessage(1, cc::proto::CompositorMessage()); EXPECT_CALL(out_processor_, - MockableProcessMessage(CompMsgEquals(2, 1U))).Times(1); + MockableProcessMessage(CompMsgEquals(2, 1U), _)).Times(1); processor_.SendCompositorMessage(2, cc::proto::CompositorMessage()); }
diff --git a/blimp/client/navigation_message_processor.cc b/blimp/client/navigation_message_processor.cc new file mode 100644 index 0000000..8181060 --- /dev/null +++ b/blimp/client/navigation_message_processor.cc
@@ -0,0 +1,138 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/client/navigation_message_processor.h" + +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/navigation.pb.h" +#include "net/base/net_errors.h" +#include "url/gurl.h" + +namespace blimp { + +NavigationMessageProcessor::NavigationMessageProcessor( + BlimpMessageProcessor* outgoing_message_processor) + : outgoing_message_processor_(outgoing_message_processor) { +} + +NavigationMessageProcessor::~NavigationMessageProcessor() { +} + +void NavigationMessageProcessor::SetDelegate( + int tab_id, + NavigationMessageDelegate* delegate) { + DCHECK(!FindDelegate(tab_id)); + delegates_[tab_id] = delegate; +} + +void NavigationMessageProcessor::RemoveDelegate(int tab_id) { + DelegateMap::iterator it = delegates_.find(tab_id); + if (it != delegates_.end()) + delegates_.erase(it); +} + +void NavigationMessageProcessor::NavigateToUrlText( + int tab_id, + const std::string& url_text) { + scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage); + blimp_message->set_target_tab_id(tab_id); + + NavigationMessage* navigation_message = blimp_message->mutable_navigation(); + navigation_message->set_type(NavigationMessage::LOAD_URL); + navigation_message->mutable_load_url()->set_url(url_text); + + outgoing_message_processor_->ProcessMessage(std::move(blimp_message), + net::CompletionCallback()); +} + +void NavigationMessageProcessor::Reload(int tab_id) { + scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage); + blimp_message->set_target_tab_id(tab_id); + + NavigationMessage* navigation_message = blimp_message->mutable_navigation(); + navigation_message->set_type(NavigationMessage::RELOAD); + + outgoing_message_processor_->ProcessMessage(std::move(blimp_message), + net::CompletionCallback()); +} + +void NavigationMessageProcessor::GoForward(int tab_id) { + scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage); + blimp_message->set_target_tab_id(tab_id); + + NavigationMessage* navigation_message = blimp_message->mutable_navigation(); + navigation_message->set_type(NavigationMessage::GO_FORWARD); + + outgoing_message_processor_->ProcessMessage(std::move(blimp_message), + net::CompletionCallback()); +} + +void NavigationMessageProcessor::GoBack(int tab_id) { + scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage); + blimp_message->set_target_tab_id(tab_id); + + NavigationMessage* navigation_message = blimp_message->mutable_navigation(); + navigation_message->set_type(NavigationMessage::GO_BACK); + + outgoing_message_processor_->ProcessMessage(std::move(blimp_message), + net::CompletionCallback()); +} + +void NavigationMessageProcessor::ProcessMessage( + scoped_ptr<BlimpMessage> message, + const net::CompletionCallback& callback) { + DCHECK(message->type() == BlimpMessage::NAVIGATION); + + int tab_id = message->target_tab_id(); + DCHECK(message->has_navigation()); + const NavigationMessage& navigation_message = message->navigation(); + + NavigationMessageDelegate* delegate = FindDelegate(tab_id); + DCHECK(delegate); + if (!delegate) + return; + + switch (navigation_message.type()) { + case NavigationMessage::NAVIGATION_STATE_CHANGED: + { + const NavigationStateChangeMessage& details = + navigation_message.navigation_state_change(); + if (details.has_url()) + delegate->OnUrlChanged(tab_id, GURL(details.url())); + + if (details.has_title()) + delegate->OnTitleChanged(tab_id, details.title()); + + if (details.has_loading()) + delegate->OnLoadingChanged(tab_id, details.loading()); + + if (details.has_favicon()) { + NOTIMPLEMENTED(); + } + } + break; + case NavigationMessage::LOAD_URL: + case NavigationMessage::GO_BACK: + case NavigationMessage::GO_FORWARD: + case NavigationMessage::RELOAD: + NOTREACHED() << "Client received unexpected navigation type."; + break; + case NavigationMessage::UNKNOWN: + NOTREACHED(); + } + + if (!callback.is_null()) + callback.Run(net::OK); +} + +NavigationMessageProcessor::NavigationMessageDelegate* +NavigationMessageProcessor::FindDelegate( + const int tab_id) { + DelegateMap::const_iterator it = delegates_.find(tab_id); + if (it != delegates_.end()) + return it->second; + return nullptr; +} + +} // namespace blimp
diff --git a/blimp/client/navigation_message_processor.h b/blimp/client/navigation_message_processor.h new file mode 100644 index 0000000..0e85bdc --- /dev/null +++ b/blimp/client/navigation_message_processor.h
@@ -0,0 +1,66 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_ +#define BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_ + +#include "base/containers/small_map.h" +#include "base/macros.h" +#include "blimp/client/blimp_client_export.h" +#include "blimp/net/blimp_message_processor.h" + +class GURL; +class SkBitmap; + +namespace blimp { + +// Handles all incoming and outgoing protobuf messages of type +// RenderWidget::NAVIGATION. Delegates can be added to be notified of incoming +// messages. +class BLIMP_CLIENT_EXPORT NavigationMessageProcessor + : public BlimpMessageProcessor { + public: + // A delegate to be notified of specific navigation events related to a + // a particular tab. + class NavigationMessageDelegate { + public: + virtual void OnUrlChanged(int tab_id, const GURL& url) = 0; + virtual void OnFaviconChanged(int tab_id, const SkBitmap& favicon) = 0; + virtual void OnTitleChanged(int tab_id, const std::string& title) = 0; + virtual void OnLoadingChanged(int tab_id, bool loading) = 0; + }; + + explicit NavigationMessageProcessor( + BlimpMessageProcessor* outgoing_message_processor); + ~NavigationMessageProcessor() override; + + // Sets a NavigationMessageDelegate to be notified of all navigation messages + // for |tab_id| from the engine. + void SetDelegate(int tab_id, NavigationMessageDelegate* delegate); + void RemoveDelegate(int tab_id); + + void NavigateToUrlText(int tab_id, const std::string& url_text); + void Reload(int tab_id); + void GoForward(int tab_id); + void GoBack(int tab_id); + + // BlimpMessageProcessor implementation. + void ProcessMessage(scoped_ptr<BlimpMessage> message, + const net::CompletionCallback& callback) override; + private: + NavigationMessageDelegate* FindDelegate(const int tab_id); + + typedef base::SmallMap<std::map<int, NavigationMessageDelegate*> > + DelegateMap; + + DelegateMap delegates_; + + BlimpMessageProcessor* outgoing_message_processor_; + + DISALLOW_COPY_AND_ASSIGN(NavigationMessageProcessor); +}; + +} // namespace blimp + +#endif // BLIMP_CLIENT_NAVIGATION_MESSAGE_PROCESSOR_H_
diff --git a/blimp/client/navigation_message_processor_unittest.cc b/blimp/client/navigation_message_processor_unittest.cc new file mode 100644 index 0000000..926ee5f --- /dev/null +++ b/blimp/client/navigation_message_processor_unittest.cc
@@ -0,0 +1,157 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/client/navigation_message_processor.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/net/test_common.h" +#include "net/base/net_errors.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "url/gurl.h" + +using testing::_; + +namespace blimp { + +class MockNavigationMessageDelegate + : public NavigationMessageProcessor::NavigationMessageDelegate { + public: + // NavigationMessageDelegate implementation. + MOCK_METHOD2(OnUrlChanged, void(int tab_id, const GURL& url)); + MOCK_METHOD2(OnFaviconChanged, void(int tab_id, const SkBitmap& favicon)); + MOCK_METHOD2(OnTitleChanged, void(int tab_id, const std::string& title)); + MOCK_METHOD2(OnLoadingChanged, void(int tab_id, bool loading)); +}; + +void SendMockNavigationStateChangedMessage(BlimpMessageProcessor* processor, + int tab_id, + const GURL* url, + const std::string* title, + const bool* loading) { + scoped_ptr<BlimpMessage> message(new BlimpMessage); + message->set_type(BlimpMessage::NAVIGATION); + message->set_target_tab_id(tab_id); + + NavigationMessage* details = message->mutable_navigation(); + details->set_type(NavigationMessage::NAVIGATION_STATE_CHANGED); + + NavigationStateChangeMessage* state = + details->mutable_navigation_state_change(); + if (url) + state->set_url(url->spec()); + + if (title) + state->set_title(*title); + + if (loading) + state->set_loading(*loading); + + processor->ProcessMessage(std::move(message), net::CompletionCallback()); +} + +MATCHER_P2(EqualsNavigateToUrlText, tab_id, text, "") { + return arg.target_tab_id() == tab_id && + arg.navigation().type() == NavigationMessage::LOAD_URL && + arg.navigation().load_url().url() == text; +} + +MATCHER_P(EqualsNavigateForward, tab_id, "") { + return arg.target_tab_id() == tab_id && + arg.navigation().type() == NavigationMessage::GO_FORWARD; +} + +MATCHER_P(EqualsNavigateBack, tab_id, "") { + return arg.target_tab_id() == tab_id && + arg.navigation().type() == NavigationMessage::GO_BACK; +} + +MATCHER_P(EqualsNavigateReload, tab_id, "") { + return arg.target_tab_id() == tab_id && + arg.navigation().type() == NavigationMessage::RELOAD; +} + + +class NavigationMessageProcessorTest : public testing::Test { + public: + NavigationMessageProcessorTest() + : processor_(&out_processor_) {} + + void SetUp() override { + processor_.SetDelegate(1, &delegate1_); + processor_.SetDelegate(2, &delegate2_); + } + + protected: + MockBlimpMessageProcessor out_processor_; + MockNavigationMessageDelegate delegate1_; + MockNavigationMessageDelegate delegate2_; + + NavigationMessageProcessor processor_; +}; + +TEST_F(NavigationMessageProcessorTest, DispatchesToCorrectDelegate) { + GURL url("https://www.google.com"); + EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1); + SendMockNavigationStateChangedMessage( + &processor_, 1, &url, nullptr, nullptr); + + EXPECT_CALL(delegate2_, OnUrlChanged(2, url)).Times(1); + SendMockNavigationStateChangedMessage( + &processor_, 2, &url, nullptr, nullptr); +} + +TEST_F(NavigationMessageProcessorTest, AllDelegateFieldsCalled) { + GURL url("https://www.google.com"); + std::string title = "Google"; + bool loading = true; + + EXPECT_CALL(delegate1_, OnUrlChanged(1, url)).Times(1); + EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1); + EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1); + SendMockNavigationStateChangedMessage(&processor_, 1, &url, &title, &loading); +} + +TEST_F(NavigationMessageProcessorTest, PartialDelegateFieldsCalled) { + std::string title = "Google"; + bool loading = true; + + EXPECT_CALL(delegate1_, OnUrlChanged(_, _)).Times(0); + EXPECT_CALL(delegate1_, OnTitleChanged(1, title)).Times(1); + EXPECT_CALL(delegate1_, OnLoadingChanged(1, loading)).Times(1); + SendMockNavigationStateChangedMessage( + &processor_, 1, nullptr, &title, &loading); +} + +TEST_F(NavigationMessageProcessorTest, TestNavigateToUrlMessage) { + std::string text = "text"; + + EXPECT_CALL(out_processor_, + MockableProcessMessage( + EqualsNavigateToUrlText(1, text), _)).Times(1); + processor_.NavigateToUrlText(1, text); +} + +TEST_F(NavigationMessageProcessorTest, TestNavigateForwardMessage) { + EXPECT_CALL(out_processor_, + MockableProcessMessage(EqualsNavigateForward(1), _)).Times(1); + processor_.GoForward(1); +} + +TEST_F(NavigationMessageProcessorTest, TestNavigateBackMessage) { + EXPECT_CALL(out_processor_, + MockableProcessMessage(EqualsNavigateBack(1), _)).Times(1); + processor_.GoBack(1); +} + +TEST_F(NavigationMessageProcessorTest, TestNavigateReloadMessage) { + EXPECT_CALL(out_processor_, + MockableProcessMessage(EqualsNavigateReload(1), _)).Times(1); + processor_.Reload(1); +} + +} // namespace blimp
diff --git a/blimp/common/proto/blimp_message.proto b/blimp/common/proto/blimp_message.proto index 505e0f44..5841cd80 100644 --- a/blimp/common/proto/blimp_message.proto +++ b/blimp/common/proto/blimp_message.proto
@@ -40,21 +40,27 @@ INPUT = 4; COMPOSITOR = 5; } + + // Sequence number of this message, used for message acknowledgement. + // The sender may omit this value if it is exactly one higher than the + // message that was previously sent. + optional int64 message_id = 1; + // Identifies the feature type of this message. // The feature-specific contents are contained in optional fields of the same // name (example: use |compositor| field for type=COMPOSITOR.) - optional Type type = 1; + optional Type type = 2; // Uniquely identifies the Blimp session that originated this message. // Session IDs are invalidated whenever new sessions are created. // If a message's |session_id| does not match the client's session ID, // then the message may have originated from a discarded session and can be // safely ignored. - optional int32 session_id = 2; + optional int32 session_id = 3; // ID of the tab that is referenced by this message. // Messages that are tab-agnostic may leave this field unset. - optional int32 target_tab_id = 3; + optional int32 target_tab_id = 4; // Feature-specific messages follow. // Only one of these fields may be set per BlimpMessage.
diff --git a/blimp/common/proto/navigation.proto b/blimp/common/proto/navigation.proto index 86270e1..7c62503 100644 --- a/blimp/common/proto/navigation.proto +++ b/blimp/common/proto/navigation.proto
@@ -30,6 +30,12 @@ // If the title changed, this will contain the new title string. optional string title = 3; + + // If the loading state changed, this will contain whether or not the page is + // loading. See WebContents::IsLoading() for more details. + // TODO(dtrainor): Figure out exactly what we want to send here. Loading may + // mean different things for different contexts (crbug.com/563626). + optional bool loading = 4; } message NavigationMessage {
diff --git a/blimp/engine/browser/BUILD.gn b/blimp/engine/browser/BUILD.gn index 95248167..714f092d 100644 --- a/blimp/engine/browser/BUILD.gn +++ b/blimp/engine/browser/BUILD.gn
@@ -54,6 +54,7 @@ "//blimp/common/proto", "//blimp/engine/common", "//blimp/net:blimp_net", + "//blimp/net:test_support", "//testing/gmock", "//testing/gtest", ]
diff --git a/blimp/engine/browser/blimp_engine_session.cc b/blimp/engine/browser/blimp_engine_session.cc index c399d544..abea9af 100644 --- a/blimp/engine/browser/blimp_engine_session.cc +++ b/blimp/engine/browser/blimp_engine_session.cc
@@ -5,6 +5,7 @@ #include "blimp/engine/browser/blimp_engine_session.h" #include "base/lazy_instance.h" +#include "base/strings/utf_string_conversions.h" #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/common/proto/control.pb.h" #include "blimp/engine/browser/blimp_browser_context.h" @@ -128,6 +129,8 @@ if (url.is_empty() || !web_contents_) return; + // TODO(dtrainor, haibinlu): Fix up the URL with url_fixer.h. If that doesn't + // produce a valid spec() then try to build a search query? content::NavigationController::LoadURLParams params(url); params.transition_type = ui::PageTransitionFromInt( ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); @@ -290,6 +293,41 @@ render_widget_processor_.SendCompositorMessage(kDummyTabId, proto); } +void BlimpEngineSession::NavigationStateChanged( + content::WebContents* source, + content::InvalidateTypes changed_flags) { + if (source != web_contents_.get() || !changed_flags) + return; + + scoped_ptr<BlimpMessage> message(new BlimpMessage); + message->set_type(BlimpMessage::NAVIGATION); + message->set_target_tab_id(kDummyTabId); + + NavigationMessage* navigation_message = message->mutable_navigation(); + navigation_message->set_type(NavigationMessage::NAVIGATION_STATE_CHANGED); + NavigationStateChangeMessage* details = + navigation_message->mutable_navigation_state_change(); + + if (changed_flags & content::InvalidateTypes::INVALIDATE_TYPE_URL) + details->set_url(source->GetURL().spec()); + + if (changed_flags & content::InvalidateTypes::INVALIDATE_TYPE_TAB) { + // TODO(dtrainor): Serialize the favicon? + NOTIMPLEMENTED(); + } + + if (changed_flags & content::InvalidateTypes::INVALIDATE_TYPE_TITLE) + details->set_title(base::UTF16ToUTF8(source->GetTitle())); + + if (changed_flags & content::InvalidateTypes::INVALIDATE_TYPE_LOAD) + details->set_loading(source->IsLoading()); + + // TODO(dtrainor, haibinlu): Send to the right BlimpMessageProcessor. + g_blimp_message_processor.Pointer()->ProcessMessage( + std::move(message), + net::CompletionCallback()); +} + void BlimpEngineSession::RenderViewHostChanged( content::RenderViewHost* old_host, content::RenderViewHost* new_host) {
diff --git a/blimp/engine/browser/blimp_engine_session.h b/blimp/engine/browser/blimp_engine_session.h index 4bba4876..e834fe3 100644 --- a/blimp/engine/browser/blimp_engine_session.h +++ b/blimp/engine/browser/blimp_engine_session.h
@@ -9,6 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "blimp/engine/browser/engine_render_widget_message_processor.h" #include "blimp/net/blimp_message_processor.h" +#include "content/public/browser/invalidate_type.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" #include "net/base/completion_callback.h" @@ -104,6 +105,8 @@ void CloseContents(content::WebContents* source) override; void ActivateContents(content::WebContents* contents) override; void ForwardCompositorProto(const std::vector<uint8_t>& proto) override; + void NavigationStateChanged(content::WebContents* source, + content::InvalidateTypes changed_flags) override; // content::WebContentsObserver implementation. void RenderViewHostChanged(content::RenderViewHost* old_host,
diff --git a/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc index fd56f4c..2d0da5e9 100644 --- a/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc +++ b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
@@ -11,6 +11,7 @@ #include "blimp/common/proto/compositor.pb.h" #include "blimp/common/proto/render_widget.pb.h" #include "blimp/net/input_message_generator.h" +#include "blimp/net/test_common.h" #include "net/base/net_errors.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,24 +26,6 @@ namespace blimp { namespace { -class MockBlimpMessageProcessor : public BlimpMessageProcessor { - public: - MockBlimpMessageProcessor() {} - - ~MockBlimpMessageProcessor() override {} - - // Adapts calls from ProcessMessage to MockableProcessMessage by - // unboxing the |message| scoped_ptr for GMock compatibility. - void ProcessMessage(scoped_ptr<BlimpMessage> message, - const net::CompletionCallback& callback) { - MockableProcessMessage(*message); - if (!callback.is_null()) - callback.Run(net::OK); - } - - MOCK_METHOD1(MockableProcessMessage, - void(const BlimpMessage& message)); -}; class MockHostRenderWidgetMessageDelegate : public EngineRenderWidgetMessageProcessor::RenderWidgetMessageDelegate { @@ -100,7 +83,7 @@ message->set_target_tab_id(tab_id); message->mutable_input()->set_render_widget_id(rw_id); - processor->ProcessMessage(message.Pass(), + processor->ProcessMessage(std::move(message), net::CompletionCallback()); } @@ -115,7 +98,7 @@ CompositorMessage* details = message->mutable_compositor(); details->set_render_widget_id(rw_id); details->set_payload(payload.data(), base::checked_cast<int>(payload.size())); - processor->ProcessMessage(message.Pass(), + processor->ProcessMessage(std::move(message), net::CompletionCallback()); } @@ -167,7 +150,7 @@ SendCompositorMessage(&processor_, 1, 1U, payload); EXPECT_CALL(out_processor_, - MockableProcessMessage(BlimpRWMsgEquals(1, 2U))).Times(1); + MockableProcessMessage(BlimpRWMsgEquals(1, 2U), _)).Times(1); processor_.OnRenderWidgetInitialized(1); EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived( @@ -191,15 +174,15 @@ std::vector<uint8_t> payload = { 'a', 'b', 'c', 'd' }; EXPECT_CALL(out_processor_, - MockableProcessMessage(BlimpRWMsgEquals(1, 2U))).Times(1); + MockableProcessMessage(BlimpRWMsgEquals(1, 2U), _)).Times(1); processor_.OnRenderWidgetInitialized(1); EXPECT_CALL(out_processor_, - MockableProcessMessage(BlimpRWMsgEquals(2, 2U))).Times(1); + MockableProcessMessage(BlimpRWMsgEquals(2, 2U), _)).Times(1); processor_.OnRenderWidgetInitialized(2); EXPECT_CALL(out_processor_, MockableProcessMessage( - BlimpCompMsgEquals(1, 2U, payload))).Times(1); + BlimpCompMsgEquals(1, 2U, payload), _)).Times(1); processor_.SendCompositorMessage(1, payload); }
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn index feb3adee..f20c77c 100644 --- a/blimp/net/BUILD.gn +++ b/blimp/net/BUILD.gn
@@ -56,6 +56,23 @@ ] } +source_set("test_support") { + testonly = true + + sources = [ + "blimp_net_test_export.h", + "test_common.cc", + "test_common.h", + ] + + deps = [ + ":blimp_net", + "//blimp/common/proto", + "//net:test_support", + "//testing/gmock", + ] +} + source_set("unit_tests") { testonly = true @@ -63,18 +80,18 @@ "blimp_connection_unittest.cc", "blimp_message_demultiplexer_unittest.cc", "blimp_message_multiplexer_unittest.cc", + "blimp_message_output_buffer_unittest.cc", "blimp_message_pump_unittest.cc", "engine_connection_manager_unittest.cc", "input_message_unittest.cc", "stream_packet_reader_unittest.cc", "stream_packet_writer_unittest.cc", "tcp_transport_unittest.cc", - "test_common.cc", - "test_common.h", ] deps = [ ":blimp_net", + ":test_support", "//base", "//base/test:run_all_unittests", "//base/test:test_support",
diff --git a/blimp/net/blimp_connection.cc b/blimp/net/blimp_connection.cc index a79ffe0..c5b0700 100644 --- a/blimp/net/blimp_connection.cc +++ b/blimp/net/blimp_connection.cc
@@ -40,7 +40,6 @@ PacketWriter* writer_; ConnectionErrorObserver* error_observer_; scoped_refptr<net::DrainableIOBuffer> buffer_; - net::CancelableCompletionCallback write_packet_callback_; net::CompletionCallback pending_process_msg_callback_; DISALLOW_COPY_AND_ASSIGN(BlimpMessageSender); @@ -72,19 +71,14 @@ return; } - write_packet_callback_.Reset(base::Bind( - &BlimpMessageSender::OnWritePacketComplete, base::Unretained(this))); pending_process_msg_callback_ = callback; - int result = writer_->WritePacket(buffer_, write_packet_callback_.callback()); - if (result != net::ERR_IO_PENDING) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(write_packet_callback_.callback(), result)); - } + writer_->WritePacket(buffer_, + base::Bind(&BlimpMessageSender::OnWritePacketComplete, + base::Unretained(this))); } void BlimpMessageSender::OnWritePacketComplete(int result) { DCHECK_NE(net::ERR_IO_PENDING, result); - write_packet_callback_.Cancel(); base::ResetAndReturn(&pending_process_msg_callback_).Run(result); if (result != net::OK) { error_observer_->OnConnectionError(result);
diff --git a/blimp/net/blimp_connection_unittest.cc b/blimp/net/blimp_connection_unittest.cc index 66d0658..759b426 100644 --- a/blimp/net/blimp_connection_unittest.cc +++ b/blimp/net/blimp_connection_unittest.cc
@@ -20,9 +20,7 @@ #include "testing/gtest/include/gtest/gtest.h" using testing::_; -using testing::DoAll; using testing::InSequence; -using testing::NotNull; using testing::Return; using testing::SaveArg; @@ -32,21 +30,17 @@ class BlimpConnectionTest : public testing::Test { public: BlimpConnectionTest() { - message1_ = CreateInputMessage(); - message2_ = CreateControlMessage(); - scoped_ptr<testing::StrictMock<MockPacketReader>> reader( - new testing::StrictMock<MockPacketReader>); - reader_ = reader.get(); scoped_ptr<testing::StrictMock<MockPacketWriter>> writer( new testing::StrictMock<MockPacketWriter>); writer_ = writer.get(); - connection_.reset(new BlimpConnection(std::move(reader), + connection_.reset(new BlimpConnection(make_scoped_ptr(new MockPacketReader), std::move(writer))); connection_->SetConnectionErrorObserver(&error_observer_); } ~BlimpConnectionTest() override {} + protected: scoped_ptr<BlimpMessage> CreateInputMessage() { scoped_ptr<BlimpMessage> msg(new BlimpMessage); msg->set_type(BlimpMessage::INPUT); @@ -59,93 +53,25 @@ return msg; } - protected: - base::MessageLoopForIO message_loop_; - scoped_ptr<BlimpMessage> message1_; - scoped_ptr<BlimpMessage> message2_; - - testing::StrictMock<MockPacketReader>* reader_; + base::MessageLoop message_loop_; testing::StrictMock<MockPacketWriter>* writer_; testing::StrictMock<MockConnectionErrorObserver> error_observer_; testing::StrictMock<MockBlimpMessageProcessor> receiver_; scoped_ptr<BlimpConnection> connection_; }; -// Reader completes reading one packet synchronously. -// Two read cases here. BlimpMessagePumpTest covers other cases. -TEST_F(BlimpConnectionTest, SyncPacketRead) { - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)); - EXPECT_CALL(*reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - Return(message1_->ByteSize()))); - connection_->SetIncomingMessageProcessor(&receiver_); -} - -// Reader completes reading one packet synchronously withe error. -TEST_F(BlimpConnectionTest, SyncPacketReadWithError) { - InSequence s; - EXPECT_CALL(*reader_, ReadPacket(NotNull(), _)) - .WillOnce(Return(net::ERR_FAILED)); - EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); - connection_->SetIncomingMessageProcessor(&receiver_); -} - -// Writer completes writing two packets synchronously. -TEST_F(BlimpConnectionTest, SyncTwoPacketsWrite) { - InSequence s; - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message1_), _)) - .WillOnce(Return(net::OK)) - .RetiresOnSaturation(); - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message2_), _)) - .WillOnce(Return(net::OK)) - .RetiresOnSaturation(); - - BlimpMessageProcessor* sender = connection_->GetOutgoingMessageProcessor(); - net::TestCompletionCallback complete_cb_1; - sender->ProcessMessage(CreateInputMessage(), - complete_cb_1.callback()); - EXPECT_EQ(net::OK, complete_cb_1.WaitForResult()); - net::TestCompletionCallback complete_cb_2; - sender->ProcessMessage(CreateControlMessage(), - complete_cb_2.callback()); - EXPECT_EQ(net::OK, complete_cb_2.WaitForResult()); -} - -// Writer completes writing two packets synchronously. -// First write succeeds, second fails. -TEST_F(BlimpConnectionTest, SyncTwoPacketsWriteWithError) { - InSequence s; - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message1_), _)) - .WillOnce(Return(net::OK)) - .RetiresOnSaturation(); - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message2_), _)) - .WillOnce(Return(net::ERR_FAILED)) - .RetiresOnSaturation(); - EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); - - BlimpMessageProcessor* sender = connection_->GetOutgoingMessageProcessor(); - net::TestCompletionCallback complete_cb_1; - sender->ProcessMessage(CreateInputMessage(), - complete_cb_1.callback()); - EXPECT_EQ(net::OK, complete_cb_1.WaitForResult()); - net::TestCompletionCallback complete_cb_2; - sender->ProcessMessage(CreateControlMessage(), - complete_cb_2.callback()); - EXPECT_EQ(net::ERR_FAILED, complete_cb_2.WaitForResult()); -} - // Write completes writing two packets asynchronously. TEST_F(BlimpConnectionTest, AsyncTwoPacketsWrite) { net::CompletionCallback write_packet_cb; InSequence s; - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message1_), _)) - .WillOnce( - DoAll(SaveArg<1>(&write_packet_cb), Return(net::ERR_IO_PENDING))) + EXPECT_CALL(*writer_, + WritePacket(BufferEqualsProto(*CreateInputMessage()), _)) + .WillOnce(SaveArg<1>(&write_packet_cb)) .RetiresOnSaturation(); - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message2_), _)) - .WillOnce( - DoAll(SaveArg<1>(&write_packet_cb), Return(net::ERR_IO_PENDING))) + EXPECT_CALL(*writer_, + WritePacket(BufferEqualsProto(*CreateControlMessage()), _)) + .WillOnce(SaveArg<1>(&write_packet_cb)) .RetiresOnSaturation(); BlimpMessageProcessor* sender = connection_->GetOutgoingMessageProcessor(); @@ -172,13 +98,13 @@ net::CompletionCallback write_packet_cb; InSequence s; - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message1_), _)) - .WillOnce( - DoAll(SaveArg<1>(&write_packet_cb), Return(net::ERR_IO_PENDING))) + EXPECT_CALL(*writer_, + WritePacket(BufferEqualsProto(*CreateInputMessage()), _)) + .WillOnce(SaveArg<1>(&write_packet_cb)) .RetiresOnSaturation(); - EXPECT_CALL(*writer_, WritePacket(BufferEqualsProto(*message2_), _)) - .WillOnce( - DoAll(SaveArg<1>(&write_packet_cb), Return(net::ERR_IO_PENDING))) + EXPECT_CALL(*writer_, + WritePacket(BufferEqualsProto(*CreateControlMessage()), _)) + .WillOnce(SaveArg<1>(&write_packet_cb)) .RetiresOnSaturation(); EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); @@ -197,5 +123,4 @@ } } // namespace - } // namespace blimp
diff --git a/blimp/net/blimp_message_output_buffer.cc b/blimp/net/blimp_message_output_buffer.cc index dd79563a..62cc259 100644 --- a/blimp/net/blimp_message_output_buffer.cc +++ b/blimp/net/blimp_message_output_buffer.cc
@@ -4,26 +4,151 @@ #include "blimp/net/blimp_message_output_buffer.h" +#include <algorithm> + #include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "net/base/net_errors.h" namespace blimp { -BlimpMessageOutputBuffer::BlimpMessageOutputBuffer() { - NOTIMPLEMENTED(); +BlimpMessageOutputBuffer::BlimpMessageOutputBuffer(int max_buffer_size_bytes) + : max_buffer_size_bytes_(max_buffer_size_bytes) {} + +BlimpMessageOutputBuffer::~BlimpMessageOutputBuffer() {} + +void BlimpMessageOutputBuffer::SetOutputProcessor( + BlimpMessageProcessor* processor) { + // Check that we are setting or removing the processor, not replacing it. + if (processor) { + DCHECK(!output_processor_); + output_processor_ = processor; + write_complete_cb_.Reset(base::Bind( + &BlimpMessageOutputBuffer::OnWriteComplete, base::Unretained(this))); + WriteNextMessageIfReady(); + } else { + DCHECK(output_processor_); + output_processor_ = nullptr; + write_complete_cb_.Cancel(); + } } -BlimpMessageOutputBuffer::~BlimpMessageOutputBuffer() { - NOTIMPLEMENTED(); +void BlimpMessageOutputBuffer::RetransmitBufferedMessages() { + DCHECK(output_processor_); + + // Prepend the entirety of |ack_buffer_| to |write_buffer_|. + write_buffer_.insert(write_buffer_.begin(), + std::make_move_iterator(ack_buffer_.begin()), + std::make_move_iterator(ack_buffer_.end())); + ack_buffer_.clear(); + + WriteNextMessageIfReady(); +} + +int BlimpMessageOutputBuffer::GetBufferByteSizeForTest() const { + return write_buffer_.size() + ack_buffer_.size(); +} + +int BlimpMessageOutputBuffer::GetUnacknowledgedMessageCountForTest() const { + return ack_buffer_.size(); } void BlimpMessageOutputBuffer::ProcessMessage( scoped_ptr<BlimpMessage> message, const net::CompletionCallback& callback) { - NOTIMPLEMENTED(); + VLOG(2) << "ProcessMessage (id=" << message->message_id() + << ", type=" << message->type() << ")"; + + message->set_message_id(++prev_message_id_); + + current_buffer_size_bytes_ += message->ByteSize(); + DCHECK_GE(max_buffer_size_bytes_, current_buffer_size_bytes_); + + write_buffer_.push_back( + make_scoped_ptr(new BufferEntry(message.Pass(), callback))); + + // Write the message + if (write_buffer_.size() == 1 && output_processor_) { + WriteNextMessageIfReady(); + } } +// Flushes acknowledged messages from the buffer and invokes their +// |callbacks|, if any. void BlimpMessageOutputBuffer::OnMessageCheckpoint(int64 message_id) { - NOTIMPLEMENTED(); + VLOG(2) << "OnMessageCheckpoint (message_id=" << message_id << ")"; + if (ack_buffer_.empty()) { + LOG(WARNING) << "Checkpoint called while buffer is empty."; + return; + } + if (message_id > prev_message_id_) { + LOG(WARNING) << "Illegal checkpoint response: " << message_id; + return; + } + + // Remove all acknowledged messages through |message_id| and invoke their + // write callbacks, if set. + while (!ack_buffer_.empty() && + ack_buffer_.front()->message->message_id() <= message_id) { + const BufferEntry& ack_entry = *ack_buffer_.front(); + current_buffer_size_bytes_ -= ack_entry.message->GetCachedSize(); + DCHECK_GE(current_buffer_size_bytes_, 0); + VLOG(3) << "Buffer size: " << current_buffer_size_bytes_ + << " (max=" << current_buffer_size_bytes_ << ")"; + + if (!ack_entry.callback.is_null()) { + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(ack_entry.callback, net::OK)); + } + + ack_buffer_.pop_front(); + } + + // An empty buffer should have a zero-byte footprint. + DCHECK(current_buffer_size_bytes_ > 0 || + (ack_buffer_.empty() && write_buffer_.empty())) + << "Expected zero-length buffer size, was " << current_buffer_size_bytes_ + << " bytes instead."; +} + +BlimpMessageOutputBuffer::BufferEntry::BufferEntry( + scoped_ptr<BlimpMessage> message, + net::CompletionCallback callback) + : message(message.Pass()), callback(callback) {} + +BlimpMessageOutputBuffer::BufferEntry::~BufferEntry() {} + +void BlimpMessageOutputBuffer::WriteNextMessageIfReady() { + if (write_buffer_.empty()) { + VLOG(2) << "Nothing to write."; + return; + } + + scoped_ptr<BlimpMessage> message_to_write( + new BlimpMessage(*write_buffer_.front()->message)); + VLOG(3) << "Writing message (id=" + << write_buffer_.front()->message->message_id() + << ", type=" << message_to_write->type() << ")"; + + output_processor_->ProcessMessage(message_to_write.Pass(), + write_complete_cb_.callback()); + VLOG(3) << "Queue size: " << write_buffer_.size(); +} + +void BlimpMessageOutputBuffer::OnWriteComplete(int result) { + DCHECK_LE(result, net::OK); + VLOG(2) << "Write complete, result=" << result; + + if (result == net::OK) { + ack_buffer_.push_back(std::move(write_buffer_.front())); + write_buffer_.pop_front(); + WriteNextMessageIfReady(); + } else { + // An error occurred while writing to the network connection. + // Stop writing more messages until a new connection is established. + DLOG(WARNING) << "Write error (result=" << result << ")"; + } } } // namespace blimp
diff --git a/blimp/net/blimp_message_output_buffer.h b/blimp/net/blimp_message_output_buffer.h index c1df574d..0a7bddf3 100644 --- a/blimp/net/blimp_message_output_buffer.h +++ b/blimp/net/blimp_message_output_buffer.h
@@ -5,10 +5,15 @@ #ifndef BLIMP_NET_BLIMP_MESSAGE_OUTPUT_BUFFER_H_ #define BLIMP_NET_BLIMP_MESSAGE_OUTPUT_BUFFER_H_ +#include <list> +#include <queue> +#include <utility> + #include "base/macros.h" #include "blimp/net/blimp_message_checkpoint_observer.h" #include "blimp/net/blimp_message_processor.h" #include "blimp/net/blimp_net_export.h" +#include "net/base/completion_callback.h" namespace blimp { @@ -16,19 +21,23 @@ // Provides a FIFO buffer for reliable, ordered message delivery. // Messages are retained for redelivery until they are acknowledged by the -// receiving end (via BlimpMessageAckObserver). +// receiving end (via BlimpMessageCheckpointObserver). +// Messages can be paired with callbacks that are invoked on successful +// message acknowledgement. // (Redelivery will be used in a future CL to implement Fast Recovery // of dropped connections.) class BLIMP_NET_EXPORT BlimpMessageOutputBuffer : public BlimpMessageProcessor, public BlimpMessageCheckpointObserver { public: - BlimpMessageOutputBuffer(); + explicit BlimpMessageOutputBuffer(int max_buffer_size_bytes); ~BlimpMessageOutputBuffer() override; - // Sets the processor to receive messages from this buffer. - // TODO(kmarshall): implement this. - void set_output_processor(BlimpMessageProcessor* processor) {} + // Sets the processor that will be used for writing buffered messages. + void SetOutputProcessor(BlimpMessageProcessor* processor); + + // Marks all messages in buffer for retransmission. + void RetransmitBufferedMessages(); // BlimpMessageProcessor implementation. // |callback|, if set, will be called once the remote end has acknowledged the @@ -37,13 +46,51 @@ const net::CompletionCallback& callback) override; // MessageCheckpointObserver implementation. - // Flushes acknowledged messages from the buffer and invokes their - // |callbacks|, if any. - // Callbacks should not destroy |this| so as to not interfere with the - // processing of any other pending callbacks. void OnMessageCheckpoint(int64 message_id) override; + int GetBufferByteSizeForTest() const; + int GetUnacknowledgedMessageCountForTest() const; + private: + struct BufferEntry { + BufferEntry(scoped_ptr<BlimpMessage> message, + net::CompletionCallback callback); + ~BufferEntry(); + + const scoped_ptr<BlimpMessage> message; + const net::CompletionCallback callback; + }; + + typedef std::list<scoped_ptr<BufferEntry>> MessageBuffer; + + // Writes the next message in the buffer if an output processor is attached + // and the buffer contains a message. + void WriteNextMessageIfReady(); + + // Receives the completion status of a write operation. + void OnWriteComplete(int result); + + BlimpMessageProcessor* output_processor_ = nullptr; + net::CancelableCompletionCallback write_complete_cb_; + + // Maximum serialized footprint of buffered messages. + int max_buffer_size_bytes_; + + // Serialized footprint of the messages contained in the write and ack + // buffers. + int current_buffer_size_bytes_ = 0; + + // The ID used by the last outgoing message. + int64 prev_message_id_ = 0; + + // List of unsent messages. + MessageBuffer write_buffer_; + + // List of messages that are sent and awaiting acknoweldgement. + // The messages in |ack_buffer_| are contiguous with the messages in + // |write_buffer_|. + MessageBuffer ack_buffer_; + DISALLOW_COPY_AND_ASSIGN(BlimpMessageOutputBuffer); };
diff --git a/blimp/net/blimp_message_output_buffer_unittest.cc b/blimp/net/blimp_message_output_buffer_unittest.cc new file mode 100644 index 0000000..2278fb4 --- /dev/null +++ b/blimp/net/blimp_message_output_buffer_unittest.cc
@@ -0,0 +1,262 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/net/blimp_message_output_buffer.h" + +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/net/test_common.h" +#include "net/base/net_errors.h" +#include "net/base/test_completion_callback.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::InvokeArgument; +using testing::Ref; +using testing::Return; +using testing::SaveArg; + +namespace blimp { +namespace { + +class BlimpMessageOutputBufferTest : public testing::Test { + public: + BlimpMessageOutputBufferTest() {} + + void SetUp() override { + input_msg_.set_type(BlimpMessage::INPUT); + input_msg_.set_message_id(1); + compositor_msg_.set_type(BlimpMessage::COMPOSITOR); + compositor_msg_.set_message_id(2); + + // Buffer should only have space for two unacknowledged messages + // (with message IDs). + ASSERT_EQ(input_msg_.ByteSize(), compositor_msg_.ByteSize()); + buffer_.reset(new BlimpMessageOutputBuffer(2 * input_msg_.GetCachedSize())); + } + + protected: + void AddOutputExpectation(const BlimpMessage& msg) { + EXPECT_CALL(output_processor_, MockableProcessMessage(EqualsProto(msg), _)) + .WillOnce(SaveArg<1>(&captured_cb_)) + .RetiresOnSaturation(); + } + + BlimpMessage WithMessageId(const BlimpMessage& message, int64 message_id) { + BlimpMessage output = message; + output.set_message_id(message_id); + return output; + } + + BlimpMessage input_msg_; + BlimpMessage compositor_msg_; + + base::MessageLoop message_loop_; + net::CompletionCallback captured_cb_; + MockBlimpMessageProcessor output_processor_; + scoped_ptr<BlimpMessageOutputBuffer> buffer_; + testing::InSequence s; +}; + +// Verify batched writes and acknowledgements. +TEST_F(BlimpMessageOutputBufferTest, SeparatelyBufferWriteAck) { + net::TestCompletionCallback complete_cb_1; + net::TestCompletionCallback complete_cb_2; + + AddOutputExpectation(input_msg_); + AddOutputExpectation(compositor_msg_); + + // Accumulate two messages. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(input_msg_)), + complete_cb_1.callback()); + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(compositor_msg_)), + complete_cb_2.callback()); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + + // Write two messages. + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->SetOutputProcessor(&output_processor_); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(2, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Both messages are acknowledged by separate checkpoints. + buffer_->OnMessageCheckpoint(1); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + EXPECT_EQ(net::OK, complete_cb_1.WaitForResult()); + buffer_->OnMessageCheckpoint(2); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + EXPECT_EQ(net::OK, complete_cb_2.WaitForResult()); +} + +// Verify buffer writes from an empty state. +TEST_F(BlimpMessageOutputBufferTest, WritesFromEmptyBuffer) { + net::TestCompletionCallback complete_cb_1; + net::TestCompletionCallback complete_cb_2; + + AddOutputExpectation(input_msg_); + AddOutputExpectation(compositor_msg_); + + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->SetOutputProcessor(&output_processor_); + + // Message #0 is buffered, sent, acknowledged. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(input_msg_)), + complete_cb_1.callback()); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + buffer_->OnMessageCheckpoint(1); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(compositor_msg_)), + complete_cb_2.callback()); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + buffer_->OnMessageCheckpoint(2); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); +} + +// Verify that a single checkpoint can be used to acknowledge two writes. +TEST_F(BlimpMessageOutputBufferTest, SharedCheckpoint) { + net::TestCompletionCallback complete_cb_1; + net::TestCompletionCallback complete_cb_2; + + AddOutputExpectation(input_msg_); + AddOutputExpectation(compositor_msg_); + + // Message #1 is written but unacknowledged. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(input_msg_)), + complete_cb_1.callback()); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->SetOutputProcessor(&output_processor_); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Message #2 is written but unacknowledged. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(compositor_msg_)), + complete_cb_2.callback()); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_TRUE(captured_cb_.is_null()); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(2, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Both messages are acknowledged in one checkpoint. + buffer_->OnMessageCheckpoint(2); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + EXPECT_EQ(net::OK, complete_cb_1.WaitForResult()); + EXPECT_EQ(net::OK, complete_cb_2.WaitForResult()); +} + +// Verify that messages that fail to write are kept in a pending write state. +TEST_F(BlimpMessageOutputBufferTest, WriteError) { + net::TestCompletionCallback complete_cb_1; + net::TestCompletionCallback complete_cb_2; + + AddOutputExpectation(input_msg_); + AddOutputExpectation(input_msg_); + + // Accumulate two messages. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(input_msg_)), + complete_cb_1.callback()); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + + // First write attempt, which fails. + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->SetOutputProcessor(&output_processor_); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::ERR_FAILED); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Simulate disconnect. + buffer_->SetOutputProcessor(nullptr); + + // Reconnect. Should immediately try to write the contents of the buffer. + buffer_->SetOutputProcessor(&output_processor_); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + buffer_->OnMessageCheckpoint(1); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + EXPECT_EQ(net::OK, complete_cb_1.WaitForResult()); +} + +// Verify that unacknowledged messages can be moved back to a pending write +// state (recovery after a lost connection.) +TEST_F(BlimpMessageOutputBufferTest, MessageRetransmit) { + net::TestCompletionCallback complete_cb_1; + net::TestCompletionCallback complete_cb_2; + + AddOutputExpectation(input_msg_); + AddOutputExpectation(compositor_msg_); + AddOutputExpectation(compositor_msg_); // Retransmitted message. + + // Accumulate two messages. + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(input_msg_)), + complete_cb_1.callback()); + buffer_->ProcessMessage(make_scoped_ptr(new BlimpMessage(compositor_msg_)), + complete_cb_2.callback()); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + + // Write two messages. + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->SetOutputProcessor(&output_processor_); + ASSERT_FALSE(captured_cb_.is_null()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(2, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(2, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Simulate disconnect & reconnect. + buffer_->SetOutputProcessor(nullptr); + buffer_->SetOutputProcessor(&output_processor_); + + // Remote end indicates that it only received message #0. + // Message #1 should be moved from an unacknowledged state to a pending write + // state. + ASSERT_TRUE(captured_cb_.is_null()); + buffer_->OnMessageCheckpoint(1); + buffer_->RetransmitBufferedMessages(); + ASSERT_FALSE(captured_cb_.is_null()); + ASSERT_EQ(1, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + base::ResetAndReturn(&captured_cb_).Run(net::OK); + ASSERT_EQ(1, buffer_->GetUnacknowledgedMessageCountForTest()); + + // Remote end acknowledges #1, buffer should be empty. + buffer_->OnMessageCheckpoint(2); + ASSERT_EQ(0, buffer_->GetBufferByteSizeForTest()); + ASSERT_EQ(0, buffer_->GetUnacknowledgedMessageCountForTest()); + EXPECT_EQ(net::OK, complete_cb_2.WaitForResult()); +} + +} // namespace +} // namespace blimp
diff --git a/blimp/net/blimp_message_pump.cc b/blimp/net/blimp_message_pump.cc index d9a250a..79082e0 100644 --- a/blimp/net/blimp_message_pump.cc +++ b/blimp/net/blimp_message_pump.cc
@@ -21,58 +21,46 @@ processor_(nullptr), buffer_(new net::GrowableIOBuffer) { DCHECK(reader_); + buffer_->SetCapacity(kMaxPacketPayloadSizeBytes); } BlimpMessagePump::~BlimpMessagePump() {} void BlimpMessagePump::SetMessageProcessor(BlimpMessageProcessor* processor) { - process_msg_callback_.Cancel(); + DCHECK(!processor_); processor_ = processor; - if (!processor_) { - read_packet_callback_.Cancel(); - } else if (read_packet_callback_.IsCancelled()) { - buffer_->SetCapacity(kMaxPacketPayloadSizeBytes); - ReadNextPacket(); - } + ReadNextPacket(); } void BlimpMessagePump::ReadNextPacket() { DCHECK(processor_); buffer_->set_offset(0); - read_packet_callback_.Reset(base::Bind( - &BlimpMessagePump::OnReadPacketComplete, base::Unretained(this))); - int result = - reader_->ReadPacket(buffer_.get(), read_packet_callback_.callback()); - if (result != net::ERR_IO_PENDING) { - // Read completed synchronously. - OnReadPacketComplete(result); - } + read_callback_.Reset(base::Bind(&BlimpMessagePump::OnReadPacketComplete, + base::Unretained(this))); + reader_->ReadPacket(buffer_.get(), read_callback_.callback()); } void BlimpMessagePump::OnReadPacketComplete(int result) { - read_packet_callback_.Cancel(); - if (result > 0) { - // The result is the size of the packet in bytes. + if (result == net::OK) { scoped_ptr<BlimpMessage> message(new BlimpMessage); - bool parse_result = - message->ParseFromArray(buffer_->StartOfBuffer(), result); - if (parse_result) { + if (message->ParseFromArray(buffer_->StartOfBuffer(), buffer_->offset())) { process_msg_callback_.Reset(base::Bind( &BlimpMessagePump::OnProcessMessageComplete, base::Unretained(this))); processor_->ProcessMessage(std::move(message), process_msg_callback_.callback()); - return; + } else { + result = net::ERR_FAILED; } - result = net::ERR_FAILED; } - if (error_observer_) + + if (result != net::OK) { error_observer_->OnConnectionError(result); + } } void BlimpMessagePump::OnProcessMessageComplete(int result) { // No error is expected from the message receiver. - DCHECK_EQ(result, net::OK); - process_msg_callback_.Cancel(); + DCHECK_EQ(net::OK, result); ReadNextPacket(); }
diff --git a/blimp/net/blimp_message_pump.h b/blimp/net/blimp_message_pump.h index e8fc0aa..d86b750 100644 --- a/blimp/net/blimp_message_pump.h +++ b/blimp/net/blimp_message_pump.h
@@ -26,13 +26,12 @@ // message, the BlimpMessagePump reads the next packet. class BLIMP_NET_EXPORT BlimpMessagePump { public: - // Caller ensures |reader| outlive this object. + // Caller ensures that |reader| outlives this object. explicit BlimpMessagePump(PacketReader* reader); ~BlimpMessagePump(); - // Sets the processor which will take blimp messages. - // Can be set multiple times, but previously set processors are discarded. + // Sets the processor which will take BlimpMessages. Can only be set once. // Caller retains the ownership of |processor|. void SetMessageProcessor(BlimpMessageProcessor* processor); @@ -47,16 +46,22 @@ // Callback when next packet is ready in |buffer_|. void OnReadPacketComplete(int result); - // Callback when |processor_| finishes processing a blimp message. + // Callback when |processor_| finishes processing a BlimpMessage. void OnProcessMessageComplete(int result); PacketReader* reader_; ConnectionErrorObserver* error_observer_; BlimpMessageProcessor* processor_; scoped_refptr<net::GrowableIOBuffer> buffer_; - net::CancelableCompletionCallback read_packet_callback_; + + // Cancelled in the event that the connection is destroyed (along with + // |this|) while a inflight callback is held by |processor_|. net::CancelableCompletionCallback process_msg_callback_; + // Cancelled to guard against |this| being called back from a completed read + // operation. + net::CancelableCompletionCallback read_callback_; + DISALLOW_COPY_AND_ASSIGN(BlimpMessagePump); };
diff --git a/blimp/net/blimp_message_pump_unittest.cc b/blimp/net/blimp_message_pump_unittest.cc index 7f9ab114..20760af 100644 --- a/blimp/net/blimp_message_pump_unittest.cc +++ b/blimp/net/blimp_message_pump_unittest.cc
@@ -50,60 +50,34 @@ scoped_ptr<BlimpMessagePump> message_pump_; }; -// Reader completes reading one packet synchronously. -TEST_F(BlimpMessagePumpTest, SyncPacketRead) { - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)); - EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - Return(message1_->ByteSize()))); - message_pump_->SetMessageProcessor(&receiver_); -} - -// Reader completes reading two packets synchronously. -TEST_F(BlimpMessagePumpTest, SyncTwoPacketsRead) { - EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - Return(message1_->ByteSize()))) - .WillOnce(DoAll(FillBufferFromMessage<0>(message2_.get()), - Return(message2_->ByteSize()))); - net::CompletionCallback process_msg_cb; - { - InSequence s; - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)) - .WillOnce(SaveArg<1>(&process_msg_cb)) - .RetiresOnSaturation(); - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message2_), _)); - } - message_pump_->SetMessageProcessor(&receiver_); - - // Trigger next packet read - process_msg_cb.Run(net::OK); -} - // Reader completes reading one packet asynchronously. -TEST_F(BlimpMessagePumpTest, AsyncPacketRead) { +TEST_F(BlimpMessagePumpTest, ReadPacket) { net::CompletionCallback read_packet_cb; + EXPECT_CALL(reader_, ReadPacket(NotNull(), _)); EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - SaveArg<1>(&read_packet_cb), Return(net::ERR_IO_PENDING))) - .WillOnce(Return(net::ERR_IO_PENDING)); + SetBufferOffset<0>(message1_->ByteSize()), + SaveArg<1>(&read_packet_cb))) + .RetiresOnSaturation(); net::CompletionCallback process_msg_cb; EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)) .WillOnce(SaveArg<1>(&process_msg_cb)); message_pump_->SetMessageProcessor(&receiver_); - read_packet_cb.Run(message1_->ByteSize()); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::OK); process_msg_cb.Run(net::OK); } // Reader completes reading two packets asynchronously. -TEST_F(BlimpMessagePumpTest, AsyncTwoPacketsRead) { +TEST_F(BlimpMessagePumpTest, ReadTwoPackets) { net::CompletionCallback read_packet_cb; EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - SaveArg<1>(&read_packet_cb), Return(net::ERR_IO_PENDING))) + SetBufferOffset<0>(message1_->ByteSize()), + SaveArg<1>(&read_packet_cb))) .WillOnce(DoAll(FillBufferFromMessage<0>(message2_.get()), - SaveArg<1>(&read_packet_cb), - Return(net::ERR_IO_PENDING))); + SetBufferOffset<0>(message2_->ByteSize()), + SaveArg<1>(&read_packet_cb))); net::CompletionCallback process_msg_cb; { InSequence s; @@ -113,77 +87,54 @@ EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message2_), _)); } message_pump_->SetMessageProcessor(&receiver_); - read_packet_cb.Run(message1_->ByteSize()); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::OK); // Trigger next packet read process_msg_cb.Run(net::OK); - read_packet_cb.Run(message2_->ByteSize()); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::OK); } // Reader completes reading two packets asynchronously. // The first read succeeds, and the second fails. -TEST_F(BlimpMessagePumpTest, AsyncTwoPacketsReadWithError) { +TEST_F(BlimpMessagePumpTest, ReadTwoPacketsWithError) { + net::CompletionCallback process_msg_cb; net::CompletionCallback read_packet_cb; EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - SaveArg<1>(&read_packet_cb), Return(net::ERR_IO_PENDING))) + SetBufferOffset<0>(message1_->ByteSize()), + SaveArg<1>(&read_packet_cb))) .WillOnce(DoAll(FillBufferFromMessage<0>(message2_.get()), - SaveArg<1>(&read_packet_cb), - Return(net::ERR_IO_PENDING))); - net::CompletionCallback process_msg_cb; - { - InSequence s; - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)) - .WillOnce(SaveArg<1>(&process_msg_cb)); - EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); - } + SetBufferOffset<0>(message2_->ByteSize()), + SaveArg<1>(&read_packet_cb))); + EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)) + .WillOnce(SaveArg<1>(&process_msg_cb)); + EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); + message_pump_->SetMessageProcessor(&receiver_); - read_packet_cb.Run(message1_->ByteSize()); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::OK); // Trigger next packet read process_msg_cb.Run(net::OK); - read_packet_cb.Run(net::ERR_FAILED); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::ERR_FAILED); } // Reader completes reading one packet synchronously, but packet is invalid TEST_F(BlimpMessagePumpTest, InvalidPacket) { + net::CompletionCallback read_packet_cb; std::string test_msg("msg"); EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromString<0>(test_msg), Return(1))); + .WillOnce(DoAll(FillBufferFromString<0>(test_msg), + SetBufferOffset<0>(test_msg.size()), + SaveArg<1>(&read_packet_cb))); EXPECT_CALL(error_observer_, OnConnectionError(net::ERR_FAILED)); - message_pump_->SetMessageProcessor(&receiver_); -} - -TEST_F(BlimpMessagePumpTest, ClearMessageProcessorAfterRead) { - net::CompletionCallback read_packet_cb; - EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - SaveArg<1>(&read_packet_cb), - Return(net::ERR_IO_PENDING))); - net::CompletionCallback process_msg_cb; - EXPECT_CALL(receiver_, MockableProcessMessage(EqualsProto(*message1_), _)) - .WillOnce(SaveArg<1>(&process_msg_cb)); message_pump_->SetMessageProcessor(&receiver_); - base::ResetAndReturn(&read_packet_cb).Run(message1_->ByteSize()); - - message_pump_->SetMessageProcessor(nullptr); - - // Completing message processing will not trigger next packet read. - base::ResetAndReturn(&process_msg_cb).Run(net::OK); -} - -TEST_F(BlimpMessagePumpTest, ClearMessageProcessorDuringRead) { - net::CompletionCallback read_packet_cb; - EXPECT_CALL(reader_, ReadPacket(NotNull(), _)) - .WillOnce(DoAll(FillBufferFromMessage<0>(message1_.get()), - SaveArg<1>(&read_packet_cb), - Return(net::ERR_IO_PENDING))); - - // Receiver will not get any message. - message_pump_->SetMessageProcessor(&receiver_); - message_pump_->SetMessageProcessor(nullptr); - base::ResetAndReturn(&read_packet_cb).Run(message1_->ByteSize()); + ASSERT_FALSE(read_packet_cb.is_null()); + base::ResetAndReturn(&read_packet_cb).Run(net::OK); } } // namespace
diff --git a/blimp/net/browser_connection_handler.cc b/blimp/net/browser_connection_handler.cc index d47623e8..9d3931cd 100644 --- a/blimp/net/browser_connection_handler.cc +++ b/blimp/net/browser_connection_handler.cc
@@ -13,10 +13,17 @@ #include "blimp/net/blimp_message_processor.h" namespace blimp { +namespace { + +// Maximum footprint of the output buffer. +// TODO(kmarshall): Use a value that's computed from the platform. +const int kMaxBufferSizeBytes = 1 << 24; + +} // namespace BrowserConnectionHandler::BrowserConnectionHandler() : demultiplexer_(new BlimpMessageDemultiplexer), - output_buffer_(new BlimpMessageOutputBuffer), + output_buffer_(new BlimpMessageOutputBuffer(kMaxBufferSizeBytes)), multiplexer_(new BlimpMessageMultiplexer(output_buffer_.get())) {} BrowserConnectionHandler::~BrowserConnectionHandler() {} @@ -33,11 +40,11 @@ // Since there is only a single Client, assume a newer connection should // replace an existing one. DropCurrentConnection(); - connection_ = connection.Pass(); + connection_ = std::move(connection); // Connect the incoming & outgoing message streams. connection_->SetIncomingMessageProcessor(demultiplexer_.get()); - output_buffer_->set_output_processor( + output_buffer_->SetOutputProcessor( connection_->GetOutgoingMessageProcessor()); } @@ -45,7 +52,7 @@ if (!connection_) return; connection_->SetIncomingMessageProcessor(nullptr); - output_buffer_->set_output_processor(nullptr); + output_buffer_->SetOutputProcessor(nullptr); connection_.reset(); }
diff --git a/blimp/net/browser_connection_handler.h b/blimp/net/browser_connection_handler.h index d739e50..03b2cd04 100644 --- a/blimp/net/browser_connection_handler.h +++ b/blimp/net/browser_connection_handler.h
@@ -49,9 +49,6 @@ private: void DropCurrentConnection(); - // Holds network resources while there is a Client connected. - scoped_ptr<BlimpConnection> connection_; - // Routes incoming messages to the relevant feature-specific handlers. scoped_ptr<BlimpMessageDemultiplexer> demultiplexer_; @@ -62,6 +59,9 @@ // message stream. scoped_ptr<BlimpMessageMultiplexer> multiplexer_; + // Holds network resources while there is a Client connected. + scoped_ptr<BlimpConnection> connection_; + DISALLOW_COPY_AND_ASSIGN(BrowserConnectionHandler); };
diff --git a/blimp/net/packet_reader.h b/blimp/net/packet_reader.h index 407e2fd..c000ab0 100644 --- a/blimp/net/packet_reader.h +++ b/blimp/net/packet_reader.h
@@ -18,14 +18,13 @@ virtual ~PacketReader() {} // Reads a packet from the connection. - // Returns the size of the packet, in bytes, if the read operation executed - // successfully. - // Returns ERR_IO_PENDING if the operation will be executed asynchronously. - // |cb| is later invoked with the packet size or an error code. - // All other return values indicate errors and caller should stop using this - // reader. - virtual int ReadPacket(const scoped_refptr<net::GrowableIOBuffer>& buf, - const net::CompletionCallback& cb) = 0; + // Passes net::OK to |cb| if the read operation executed successfully. + // Sets |buf.offset()| to the received message's size, and invokes |cb| with + // net::OK result on success. + // All other values indicate errors. + // |callback| will not be invoked if |this| is deleted. + virtual void ReadPacket(const scoped_refptr<net::GrowableIOBuffer>& buf, + const net::CompletionCallback& cb) = 0; }; } // namespace blimp
diff --git a/blimp/net/packet_writer.h b/blimp/net/packet_writer.h index e5dbb9a..8c7b9ca 100644 --- a/blimp/net/packet_writer.h +++ b/blimp/net/packet_writer.h
@@ -21,14 +21,11 @@ public: virtual ~PacketWriter() {} - // Writes a packet of at least one byte in size to a connection. - // - // Returns net::OK or an error code if the operation executed successfully. - // Returns ERR_IO_PENDING if the operation will be executed asynchronously. - // |cb| is later invoked with net::OK or an error code. - // An error code indicates that caller should stop using this writer. - virtual int WritePacket(scoped_refptr<net::DrainableIOBuffer> data, - const net::CompletionCallback& callback) = 0; + // Invokes |cb| with net::OK if the write operation executed successfully. + // All other values indicate unrecoverable errors. + // |callback| must not be invoked if |this| is deleted. + virtual void WritePacket(scoped_refptr<net::DrainableIOBuffer> data, + const net::CompletionCallback& callback) = 0; }; } // namespace blimp
diff --git a/blimp/net/stream_packet_reader.cc b/blimp/net/stream_packet_reader.cc index 8da61302..e5007486 100644 --- a/blimp/net/stream_packet_reader.cc +++ b/blimp/net/stream_packet_reader.cc
@@ -9,6 +9,7 @@ #include "base/callback_helpers.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" #include "base/sys_byteorder.h" #include "blimp/net/common.h" #include "net/base/io_buffer.h" @@ -42,7 +43,7 @@ StreamPacketReader::~StreamPacketReader() {} -int StreamPacketReader::ReadPacket( +void StreamPacketReader::ReadPacket( const scoped_refptr<net::GrowableIOBuffer>& buf, const net::CompletionCallback& callback) { DCHECK_EQ(ReadState::IDLE, read_state_); @@ -54,17 +55,17 @@ read_state_ = ReadState::HEADER; int result = DoReadLoop(net::OK); - if (result == net::ERR_IO_PENDING) { - // Store the completion callback to invoke when read completes - // asynchronously. - callback_ = callback; - } else { + if (result != net::ERR_IO_PENDING) { // Release the payload buffer, since the read operation has completed // synchronously. payload_buffer_ = nullptr; - } - return result; + // Adapt synchronous completion to an asynchronous style. + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, result)); + } else { + callback_ = callback; + } } int StreamPacketReader::DoReadLoop(int result) { @@ -134,7 +135,7 @@ // Finished reading the payload. read_state_ = ReadState::IDLE; - return payload_size_; + return net::OK; } void StreamPacketReader::OnReadComplete(int result) {
diff --git a/blimp/net/stream_packet_reader.h b/blimp/net/stream_packet_reader.h index 4468638d..21a6dab 100644 --- a/blimp/net/stream_packet_reader.h +++ b/blimp/net/stream_packet_reader.h
@@ -33,8 +33,8 @@ ~StreamPacketReader() override; // PacketReader implementation. - int ReadPacket(const scoped_refptr<net::GrowableIOBuffer>& buf, - const net::CompletionCallback& cb) override; + void ReadPacket(const scoped_refptr<net::GrowableIOBuffer>& buf, + const net::CompletionCallback& cb) override; private: enum class ReadState {
diff --git a/blimp/net/stream_packet_reader_unittest.cc b/blimp/net/stream_packet_reader_unittest.cc index 61419cf..5777d4d 100644 --- a/blimp/net/stream_packet_reader_unittest.cc +++ b/blimp/net/stream_packet_reader_unittest.cc
@@ -5,6 +5,7 @@ #include <stddef.h> #include <string> +#include "base/message_loop/message_loop.h" #include "base/sys_byteorder.h" #include "blimp/net/common.h" #include "blimp/net/stream_packet_reader.h" @@ -41,11 +42,10 @@ ~StreamPacketReaderTest() override {} - int ReadPacket() { - return data_reader_.ReadPacket(buffer_, callback_.callback()); - } + void ReadPacket() { data_reader_.ReadPacket(buffer_, callback_.callback()); } protected: + base::MessageLoop message_loop_; scoped_refptr<net::GrowableIOBuffer> buffer_; std::string test_msg_; net::TestCompletionCallback callback_; @@ -65,12 +65,11 @@ .WillOnce(DoAll(FillBufferFromString<0>(test_msg_), SaveArg<2>(&socket_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); socket_cb.Run(kPacketHeaderSizeBytes); socket_cb.Run(test_msg_.size()); - int rv = callback_.WaitForResult(); - - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); } @@ -89,13 +88,12 @@ .WillOnce( DoAll(FillBufferFromString<0>(test_msg_), Return(test_msg_.size()))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); EXPECT_FALSE(callback_.have_result()); socket_cb.Run(kPacketHeaderSizeBytes); - int rv = callback_.WaitForResult(); - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); } @@ -110,12 +108,10 @@ .WillOnce(DoAll(FillBufferFromString<0>(test_msg_), SaveArg<2>(&socket_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); socket_cb.Run(test_msg_.size()); - int rv = callback_.WaitForResult(); - - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); } @@ -130,12 +126,10 @@ .WillOnce( DoAll(FillBufferFromString<0>(test_msg_), Return(test_msg_.size()))); - int rv = ReadPacket(); - - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); + ReadPacket(); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); - EXPECT_FALSE(callback_.have_result()); } // Successful read of 2 messages, header and payload reads all completing @@ -168,13 +162,14 @@ DoAll(FillBufferFromString<0>(test_msg2), Return(test_msg2.size()))) .RetiresOnSaturation(); - int rv = ReadPacket(); + ReadPacket(); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); - rv = ReadPacket(); - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg2.size())); + ReadPacket(); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg2.size()), buffer_->offset()); + EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); EXPECT_FALSE(callback_.have_result()); } @@ -210,23 +205,17 @@ SaveArg<2>(&socket_cb), Return(net::ERR_IO_PENDING))) .RetiresOnSaturation(); - EXPECT_EQ(net::ERR_IO_PENDING, - data_reader_.ReadPacket(buffer_, read_cb1.callback())); + data_reader_.ReadPacket(buffer_, read_cb1.callback()); socket_cb.Run(kPacketHeaderSizeBytes); socket_cb.Run(test_msg_.size()); - int rv = read_cb1.WaitForResult(); + EXPECT_EQ(net::OK, read_cb1.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); - - EXPECT_EQ(net::ERR_IO_PENDING, - data_reader_.ReadPacket(buffer_, read_cb2.callback())); + data_reader_.ReadPacket(buffer_, read_cb2.callback()); socket_cb.Run(kPacketHeaderSizeBytes); socket_cb.Run(test_msg_.size()); - rv = read_cb2.WaitForResult(); - - EXPECT_GT(rv, 0); - EXPECT_EQ(rv, static_cast<int>(test_msg_.size())); + EXPECT_EQ(net::OK, read_cb2.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); EXPECT_TRUE(BufferStartsWith(buffer_.get(), test_msg_)); } @@ -250,7 +239,7 @@ EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size(), _)) .WillOnce(Return(net::ERR_IO_PENDING)); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); cb.Run(1); cb.Run(kPacketHeaderSizeBytes - 1); } @@ -268,7 +257,7 @@ EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size(), _)) .WillOnce(DoAll(FillBufferFromString<0>(test_msg_.substr(0, 1)), SaveArg<2>(&cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size() - 1, _)) .WillOnce(DoAll( FillBufferFromString<0>(test_msg_.substr(1, test_msg_.size() - 1)), @@ -276,10 +265,8 @@ cb.Run(1); cb.Run(test_msg_.size() - 1); - int rv = callback_.WaitForResult(); - - EXPECT_GT(rv, 0); - EXPECT_EQ(static_cast<int>(test_msg_.size()), rv); + EXPECT_EQ(net::OK, callback_.WaitForResult()); + EXPECT_EQ(static_cast<int>(test_msg_.size()), buffer_->offset()); } // Verify that synchronous header read errors are reported correctly. @@ -287,7 +274,8 @@ net::CompletionCallback cb; EXPECT_CALL(socket_, Read(NotNull(), kPacketHeaderSizeBytes, _)) .WillOnce(Return(net::ERR_FAILED)); - EXPECT_EQ(net::ERR_FAILED, ReadPacket()); + ReadPacket(); + EXPECT_EQ(net::ERR_FAILED, callback_.WaitForResult()); } // Verify that synchronous payload read errors are reported correctly. @@ -300,7 +288,8 @@ EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size(), _)) .WillOnce(Return(net::ERR_FAILED)); - EXPECT_EQ(net::ERR_FAILED, ReadPacket()); + ReadPacket(); + EXPECT_EQ(net::ERR_FAILED, callback_.WaitForResult()); } // Verify that async header read errors are reported correctly. @@ -312,7 +301,7 @@ .WillOnce(DoAll(FillBufferFromString<0>(EncodeHeader(test_msg_.size())), SaveArg<2>(&cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); cb.Run(net::ERR_FAILED); EXPECT_EQ(net::ERR_FAILED, callback_.WaitForResult()); } @@ -327,7 +316,7 @@ EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size(), _)) .WillOnce(DoAll(SaveArg<2>(&cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, ReadPacket()); + ReadPacket(); cb.Run(net::ERR_FAILED); EXPECT_EQ(net::ERR_FAILED, callback_.WaitForResult()); } @@ -343,8 +332,7 @@ .WillOnce(DoAll(FillBufferFromString<0>(EncodeHeader(test_msg_.size())), SaveArg<2>(&cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - reader->ReadPacket(buffer_, callback_.callback())); + reader->ReadPacket(buffer_, callback_.callback()); reader.reset(); // Delete the reader object. cb.Run(kPacketHeaderSizeBytes); // Complete the socket operation. } @@ -360,8 +348,7 @@ Return(kPacketHeaderSizeBytes))); EXPECT_CALL(socket_, Read(NotNull(), test_msg_.size(), _)) .WillOnce(DoAll(SaveArg<2>(&cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - reader->ReadPacket(buffer_, callback_.callback())); + reader->ReadPacket(buffer_, callback_.callback()); reader.reset(); // Delete the reader object. cb.Run(net::ERR_FAILED); // Complete the socket operation. @@ -374,7 +361,8 @@ Return(kPacketHeaderSizeBytes))) .RetiresOnSaturation(); - EXPECT_EQ(net::ERR_INVALID_RESPONSE, ReadPacket()); + ReadPacket(); + EXPECT_EQ(net::ERR_INVALID_RESPONSE, callback_.WaitForResult()); } // Verify that an illegally large payloads is reported as an erroneous inputs. @@ -384,7 +372,8 @@ DoAll(FillBufferFromString<0>(EncodeHeader(kTestMaxBufferSize + 1)), Return(kPacketHeaderSizeBytes))); - EXPECT_EQ(net::ERR_INVALID_RESPONSE, ReadPacket()); + ReadPacket(); + EXPECT_EQ(net::ERR_INVALID_RESPONSE, callback_.WaitForResult()); } } // namespace
diff --git a/blimp/net/stream_packet_writer.cc b/blimp/net/stream_packet_writer.cc index 221cdd17..943f9a9 100644 --- a/blimp/net/stream_packet_writer.cc +++ b/blimp/net/stream_packet_writer.cc
@@ -47,15 +47,11 @@ StreamPacketWriter::~StreamPacketWriter() {} -int StreamPacketWriter::WritePacket(scoped_refptr<net::DrainableIOBuffer> data, - const net::CompletionCallback& callback) { +void StreamPacketWriter::WritePacket(scoped_refptr<net::DrainableIOBuffer> data, + const net::CompletionCallback& callback) { DCHECK_EQ(WriteState::IDLE, write_state_); DCHECK(data); - if (data->BytesRemaining() == 0) { - // The packet is empty; your argument is invalid. - DLOG(ERROR) << "Attempted to write zero-length packet."; - return net::ERR_INVALID_ARGUMENT; - } + CHECK(data->BytesRemaining()); write_state_ = WriteState::HEADER; header_buffer_->SetOffset(0); @@ -63,18 +59,18 @@ base::HostToNet32(data->BytesRemaining()); payload_buffer_ = data; - int result = DoWriteLoop(false); - if (result == net::ERR_IO_PENDING) { - // Store the completion callback to invoke when DoWriteLoop completes - // asynchronously. - callback_ = callback; - } else { + int result = DoWriteLoop(net::OK); + if (result != net::ERR_IO_PENDING) { // Release the payload buffer, since the write operation has completed // synchronously. payload_buffer_ = nullptr; - } - return result; + // Adapt synchronous completion to an asynchronous style. + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, result)); + } else { + callback_ = callback; + } } int StreamPacketWriter::DoWriteLoop(int result) {
diff --git a/blimp/net/stream_packet_writer.h b/blimp/net/stream_packet_writer.h index c618eba..071a8f0 100644 --- a/blimp/net/stream_packet_writer.h +++ b/blimp/net/stream_packet_writer.h
@@ -35,8 +35,8 @@ ~StreamPacketWriter() override; // PacketWriter implementation. - int WritePacket(scoped_refptr<net::DrainableIOBuffer> data, - const net::CompletionCallback& callback) override; + void WritePacket(scoped_refptr<net::DrainableIOBuffer> data, + const net::CompletionCallback& callback) override; private: enum class WriteState {
diff --git a/blimp/net/stream_packet_writer_unittest.cc b/blimp/net/stream_packet_writer_unittest.cc index c8014f94..3212e928 100644 --- a/blimp/net/stream_packet_writer_unittest.cc +++ b/blimp/net/stream_packet_writer_unittest.cc
@@ -35,15 +35,13 @@ test_data_str_.size())), message_writer_(&socket_) {} - ~StreamPacketWriterTest() override {} - protected: const std::string test_data_str_ = "U WOT M8"; scoped_refptr<net::DrainableIOBuffer> test_data_; + base::MessageLoop message_loop_; MockStreamSocket socket_; StreamPacketWriter message_writer_; - base::MessageLoop message_loop_; testing::InSequence mock_sequence_; private: @@ -56,20 +54,14 @@ net::CompletionCallback header_cb; net::CompletionCallback payload_cb; - // Write header. EXPECT_CALL(socket_, Write(BufferEquals(EncodeHeader(test_data_str_.size())), kPacketHeaderSizeBytes, _)) .WillOnce(DoAll(SaveArg<2>(&header_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - message_writer_.WritePacket(test_data_, writer_cb.callback())); - Mock::VerifyAndClearExpectations(&socket_); - - // Write payload. + message_writer_.WritePacket(test_data_, writer_cb.callback()); EXPECT_CALL(socket_, Write(BufferEquals(test_data_str_), test_data_str_.size(), _)) .WillOnce(DoAll(SaveArg<2>(&payload_cb), Return(net::ERR_IO_PENDING))); header_cb.Run(kPacketHeaderSizeBytes); - Mock::VerifyAndClearExpectations(&socket_); payload_cb.Run(test_data_str_.size()); EXPECT_EQ(net::OK, writer_cb.WaitForResult()); @@ -100,8 +92,7 @@ .WillOnce(DoAll(SaveArg<2>(&payload_cb), Return(net::ERR_IO_PENDING))) .RetiresOnSaturation(); - EXPECT_EQ(net::ERR_IO_PENDING, - message_writer_.WritePacket(test_data_, writer_cb.callback())); + message_writer_.WritePacket(test_data_, writer_cb.callback()); // Header is written - first one byte, then the remainder. header_cb.Run(1); @@ -127,8 +118,7 @@ Write(BufferEquals(test_data_str_), test_data_str_.size(), _)) .WillOnce(DoAll(SaveArg<2>(&payload_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - message_writer_.WritePacket(test_data_, writer_cb.callback())); + message_writer_.WritePacket(test_data_, writer_cb.callback()); header_cb.Run(kPacketHeaderSizeBytes); payload_cb.Run(net::ERR_CONNECTION_RESET); @@ -138,15 +128,16 @@ // Successful write with 1 sync header write and 1 sync payload write. TEST_F(StreamPacketWriterTest, TestWriteSync) { net::TestCompletionCallback writer_cb; + EXPECT_CALL(socket_, Write(BufferEquals(EncodeHeader(test_data_str_.size())), kPacketHeaderSizeBytes, _)) .WillOnce(Return(kPacketHeaderSizeBytes)); EXPECT_CALL(socket_, Write(BufferEquals(test_data_str_), test_data_str_.size(), _)) .WillOnce(Return(test_data_str_.size())); - EXPECT_EQ(net::OK, - message_writer_.WritePacket(test_data_, writer_cb.callback())); - EXPECT_FALSE(writer_cb.have_result()); + + message_writer_.WritePacket(test_data_, writer_cb.callback()); + EXPECT_EQ(net::OK, writer_cb.WaitForResult()); } // Successful write with 2 sync header writes and 2 sync payload writes. @@ -167,21 +158,8 @@ payload.size() - 1, _)) .WillOnce(Return(payload.size() - 1)); - EXPECT_EQ(net::OK, - message_writer_.WritePacket(test_data_, writer_cb.callback())); - EXPECT_FALSE(writer_cb.have_result()); -} - -// Verify that zero-length packets are rejected. -TEST_F(StreamPacketWriterTest, TestZeroLengthPacketsRejected) { - net::TestCompletionCallback writer_cb; - - EXPECT_EQ(net::ERR_INVALID_ARGUMENT, - message_writer_.WritePacket( - new net::DrainableIOBuffer(new net::IOBuffer(0), 0), - writer_cb.callback())); - - EXPECT_FALSE(writer_cb.have_result()); + message_writer_.WritePacket(test_data_, writer_cb.callback()); + EXPECT_EQ(net::OK, writer_cb.WaitForResult()); } // Sync socket error while writing header data. @@ -192,9 +170,8 @@ kPacketHeaderSizeBytes, _)) .WillOnce(Return(net::ERR_FAILED)); - EXPECT_EQ(net::ERR_FAILED, - message_writer_.WritePacket(test_data_, writer_cb.callback())); - + message_writer_.WritePacket(test_data_, writer_cb.callback()); + EXPECT_EQ(net::ERR_FAILED, writer_cb.WaitForResult()); EXPECT_EQ(net::ERR_EMPTY_RESPONSE, writer_cb.GetResult(net::ERR_EMPTY_RESPONSE)); EXPECT_FALSE(writer_cb.have_result()); @@ -211,9 +188,8 @@ Write(BufferEquals(test_data_str_), test_data_str_.size(), _)) .WillOnce(Return(net::ERR_FAILED)); - EXPECT_EQ(net::ERR_FAILED, - message_writer_.WritePacket(test_data_, writer_cb.callback())); - EXPECT_FALSE(writer_cb.have_result()); + message_writer_.WritePacket(test_data_, writer_cb.callback()); + EXPECT_EQ(net::ERR_FAILED, writer_cb.WaitForResult()); } // Verify that asynchronous header write completions don't cause a @@ -228,8 +204,7 @@ EXPECT_CALL(socket_, Write(BufferEquals(EncodeHeader(test_data_str_.size())), kPacketHeaderSizeBytes, _)) .WillOnce(DoAll(SaveArg<2>(&header_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - writer->WritePacket(test_data_, writer_cb.callback())); + writer->WritePacket(test_data_, writer_cb.callback()); Mock::VerifyAndClearExpectations(&socket_); // Header write completion callback is invoked after the writer died. @@ -252,8 +227,7 @@ Write(BufferEquals(test_data_str_), test_data_str_.size(), _)) .WillOnce(DoAll(SaveArg<2>(&payload_cb), Return(net::ERR_IO_PENDING))); - EXPECT_EQ(net::ERR_IO_PENDING, - writer->WritePacket(test_data_, writer_cb.callback())); + writer->WritePacket(test_data_, writer_cb.callback()); // Header write completes successfully. header_cb.Run(kPacketHeaderSizeBytes);
diff --git a/blimp/net/test_common.h b/blimp/net/test_common.h index ca766a6b..58ee2f6 100644 --- a/blimp/net/test_common.h +++ b/blimp/net/test_common.h
@@ -35,7 +35,6 @@ } // Checks if two proto messages are the same. -// TODO(kmarshall): promote to a shared testing library. MATCHER_P(EqualsProto, message, "") { std::string expected_serialized; std::string actual_serialized; @@ -49,7 +48,7 @@ // message (type: BlimpMessage) The message to compare with |arg|. MATCHER_P(BufferEqualsProto, message, "") { BlimpMessage actual_message; - actual_message.ParseFromArray(arg->data(), arg->BytesRemaining()); + actual_message.ParseFromArray(arg->data(), message.ByteSize()); std::string expected_serialized; std::string actual_serialized; message.SerializeToString(&expected_serialized); @@ -67,7 +66,12 @@ memcpy(testing::get<buf_idx>(args)->data(), str.data(), str.size()); } -// GMock action that writes data from a blimp message to an IOBuffer . +// Returns true if |buf| has a prefix of |str|. +// Behavior is undefined if len(buf) < len(str). +bool BufferStartsWith(net::GrowableIOBuffer* buf, const std::string& str); + +// GMock action that writes data from a BlimpMessage to a GrowableIOBuffer. +// Advances the buffer's |offset| to the end of the message. // // buf_idx (template parameter 0): 0-based index of the IOBuffer arg. // message: the blimp message containing data to be written to the IOBuffer @@ -76,6 +80,14 @@ AND_1_VALUE_PARAMS(message)) { message->SerializeToArray(testing::get<buf_idx>(args)->data(), message->ByteSize()); + testing::get<buf_idx>(args)->set_offset(message->ByteSize()); +} + +// Calls |set_offset()| for a GrowableIOBuffer. +ACTION_TEMPLATE(SetBufferOffset, + HAS_1_TEMPLATE_PARAMS(int, buf_idx), + AND_1_VALUE_PARAMS(offset)) { + testing::get<buf_idx>(args)->set_offset(offset); } // Formats a string-based representation of a BlimpMessage header. @@ -139,8 +151,8 @@ ~MockPacketReader() override; MOCK_METHOD2(ReadPacket, - int(const scoped_refptr<net::GrowableIOBuffer>&, - const net::CompletionCallback&)); + void(const scoped_refptr<net::GrowableIOBuffer>&, + const net::CompletionCallback&)); }; class MockPacketWriter : public PacketWriter { @@ -149,8 +161,8 @@ ~MockPacketWriter() override; MOCK_METHOD2(WritePacket, - int(scoped_refptr<net::DrainableIOBuffer>, - const net::CompletionCallback&)); + void(scoped_refptr<net::DrainableIOBuffer>, + const net::CompletionCallback&)); }; class MockConnectionErrorObserver : public ConnectionErrorObserver { @@ -177,10 +189,6 @@ const net::CompletionCallback& callback)); }; -// Returns true if |buf| has a prefix of |str|. -// Behavior is undefined if len(buf) < len(str). -bool BufferStartsWith(net::GrowableIOBuffer* buf, const std::string& str); - } // namespace blimp #endif // BLIMP_NET_TEST_COMMON_H_
diff --git a/build/android/devil/android/device_utils.py b/build/android/devil/android/device_utils.py index aee5d7c..400c517 100644 --- a/build/android/devil/android/device_utils.py +++ b/build/android/devil/android/device_utils.py
@@ -31,6 +31,7 @@ from devil.android import logcat_monitor from devil.android import md5sum from devil.android.sdk import adb_wrapper +from devil.android.sdk import gce_adb_wrapper from devil.android.sdk import intent from devil.android.sdk import keyevent from devil.android.sdk import split_select @@ -95,6 +96,7 @@ r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') _GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]') +_IPV4_ADDRESS_RE = re.compile(r'([0-9]{1,3}\.){3}[0-9]{1,3}\:[0-9]{4,5}') @decorators.WithExplicitTimeoutAndRetries( _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) @@ -152,6 +154,20 @@ return ''.join(s for line in lines for s in (line, '\n')) +def _IsGceInstance(serial): + return _IPV4_ADDRESS_RE.match(serial) + + +def _CreateAdbWrapper(device): + if _IsGceInstance(str(device)): + return gce_adb_wrapper.GceAdbWrapper(str(device)) + else: + if isinstance(device, adb_wrapper.AdbWrapper): + return device + else: + return adb_wrapper.AdbWrapper(device) + + class DeviceUtils(object): _MAX_ADB_COMMAND_LENGTH = 512 @@ -182,7 +198,7 @@ """ self.adb = None if isinstance(device, basestring): - self.adb = adb_wrapper.AdbWrapper(device) + self.adb = _CreateAdbWrapper(device) elif isinstance(device, adb_wrapper.AdbWrapper): self.adb = device else: @@ -2054,8 +2070,11 @@ return True return False - return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices() - if not blacklisted(adb)] + devices = [] + for adb in adb_wrapper.AdbWrapper.Devices(): + if not blacklisted(adb): + devices.append(cls(_CreateAdbWrapper(adb), **kwargs)) + return devices @decorators.WithTimeoutAndRetriesFromInstance() def RestartAdbd(self, timeout=None, retries=None):
diff --git a/build/android/devil/android/sdk/adb_wrapper.py b/build/android/devil/android/sdk/adb_wrapper.py index 5a81c7f..3ab7ddc 100644 --- a/build/android/devil/android/sdk/adb_wrapper.py +++ b/build/android/devil/android/sdk/adb_wrapper.py
@@ -29,7 +29,7 @@ _READY_STATE = 'device' -def _VerifyLocalFileExists(path): +def VerifyLocalFileExists(path): """Verifies a local file exists. Args: @@ -226,7 +226,7 @@ timeout: (optional) Timeout per try in seconds. retries: (optional) Number of retries to attempt. """ - _VerifyLocalFileExists(local) + VerifyLocalFileExists(local) self._RunDeviceAdbCmd(['push', local, remote], timeout, retries) def Pull(self, remote, local, timeout=60*5, retries=_DEFAULT_RETRIES): @@ -241,7 +241,7 @@ cmd = ['pull', remote, local] self._RunDeviceAdbCmd(cmd, timeout, retries) try: - _VerifyLocalFileExists(local) + VerifyLocalFileExists(local) except IOError: raise device_errors.AdbCommandFailedError( cmd, 'File not found on host: %s' % local, device_serial=str(self)) @@ -450,7 +450,7 @@ timeout: (optional) Timeout per try in seconds. retries: (optional) Number of retries to attempt. """ - _VerifyLocalFileExists(apk_path) + VerifyLocalFileExists(apk_path) cmd = ['install'] if forward_lock: cmd.append('-l') @@ -480,7 +480,7 @@ partial: (optional) Package ID if apk_paths doesn't include all .apks. """ for path in apk_paths: - _VerifyLocalFileExists(path) + VerifyLocalFileExists(path) cmd = ['install-multiple'] if forward_lock: cmd.append('-l') @@ -547,7 +547,7 @@ assert bool(packages) ^ bool(include_all), ( 'Provide \'packages\' or set \'include_all\' but not both.') ret = self._RunDeviceAdbCmd(cmd, timeout, retries) - _VerifyLocalFileExists(path) + VerifyLocalFileExists(path) return ret def Restore(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES): @@ -558,7 +558,7 @@ timeout: (optional) Timeout per try in seconds. retries: (optional) Number of retries to attempt. """ - _VerifyLocalFileExists(path) + VerifyLocalFileExists(path) self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries) def WaitForDevice(self, timeout=60*5, retries=_DEFAULT_RETRIES):
diff --git a/build/android/devil/android/sdk/gce_adb_wrapper.py b/build/android/devil/android/sdk/gce_adb_wrapper.py new file mode 100644 index 0000000..60ec364 --- /dev/null +++ b/build/android/devil/android/sdk/gce_adb_wrapper.py
@@ -0,0 +1,145 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Provides a work around for various adb commands on android gce instances. + +Some adb commands don't work well when the device is a cloud vm, namely +'push' and 'pull'. With gce instances, moving files through adb can be +painfully slow and hit timeouts, so the methods here just use scp instead. +""" +# pylint: disable=unused-argument + +import logging +import os +import subprocess + +from devil.android import device_errors +from devil.android.sdk import adb_wrapper +from devil.utils import cmd_helper + + +# SSH key file for accessing the instances. The keys are created at +# startup and removed & revoked at teardown. +_SSH_KEY_FILE = '/tmp/ssh_android_gce_instance' + + +class GceAdbWrapper(adb_wrapper.AdbWrapper): + def __init__(self, device_serial): + super(GceAdbWrapper, self).__init__(device_serial) + self._instance_ip = self.Shell('getprop net.gce.ip_address').strip() + + #override + def Push(self, local, remote, **kwargs): + """Pushes an object from the host to the gce instance. + + Args: + local: Path on the host filesystem. + remote: Path on the instance filesystem. + """ + adb_wrapper.VerifyLocalFileExists(_SSH_KEY_FILE) + adb_wrapper.VerifyLocalFileExists(local) + if os.path.isdir(local): + self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(remote)) + + # When the object to be pushed is a directory, adb merges the source dir + # with the destination dir. So if local is a dir, just scp its contents. + for f in os.listdir(local): + self._PushObject(os.path.join(local, f), os.path.join(remote, f)) + self.Shell('chmod 777 %s' % + cmd_helper.SingleQuote(os.path.join(remote, f))) + else: + parent_dir = remote[0:remote.rfind('/')] + if parent_dir: + self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(parent_dir)) + self._PushObject(local, remote) + self.Shell('chmod 777 %s' % cmd_helper.SingleQuote(remote)) + + def _PushObject(self, local, remote): + """Copies an object from the host to the gce instance using scp. + + Args: + local: Path on the host filesystem. + remote: Path on the instance filesystem. + """ + cmd = [ + 'scp', + '-r', + '-i', _SSH_KEY_FILE, + '-o', 'UserKnownHostsFile=/dev/null', + '-o', 'StrictHostKeyChecking=no', + local, + 'root@%s:%s' % (self._instance_ip, remote) + ] + status, _ = cmd_helper.GetCmdStatusAndOutput(cmd) + if status: + raise device_errors.AdbCommandFailedError( + cmd, 'File not reachable on host: %s' % local, + device_serial=str(self)) + + #override + def Pull(self, remote, local, **kwargs): + """Pulls a file from the gce instance to the host. + + Args: + remote: Path on the instance filesystem. + local: Path on the host filesystem. + """ + adb_wrapper.VerifyLocalFileExists(_SSH_KEY_FILE) + cmd = [ + 'scp', + '-p', + '-r', + '-i', _SSH_KEY_FILE, + '-o', 'UserKnownHostsFile=/dev/null', + '-o', 'StrictHostKeyChecking=no', + 'root@%s:%s' % (self._instance_ip, remote), + local, + ] + status, _ = cmd_helper.GetCmdStatusAndOutput(cmd) + if status: + raise device_errors.AdbCommandFailedError( + cmd, 'File not reachable on host: %s' % local, + device_serial=str(self)) + + try: + adb_wrapper.VerifyLocalFileExists(local) + except (subprocess.CalledProcessError, IOError): + logging.exception('Error when pulling files from android instance.') + raise device_errors.AdbCommandFailedError( + cmd, 'File not reachable on host: %s' % local, + device_serial=str(self)) + + #override + def Install(self, apk_path, forward_lock=False, reinstall=False, + sd_card=False, **kwargs): + """Installs an apk on the gce instance + + Args: + apk_path: Host path to the APK file. + forward_lock: (optional) If set forward-locks the app. + reinstall: (optional) If set reinstalls the app, keeping its data. + sd_card: (optional) If set installs on the SD card. + """ + adb_wrapper.VerifyLocalFileExists(_SSH_KEY_FILE) + adb_wrapper.VerifyLocalFileExists(apk_path) + cmd = ['install'] + if forward_lock: + cmd.append('-l') + if reinstall: + cmd.append('-r') + if sd_card: + cmd.append('-s') + self.Push(apk_path, '/data/local/tmp/tmp.apk') + cmd = ['pm'] + cmd + cmd.append('/data/local/tmp/tmp.apk') + output = self.Shell(' '.join(cmd)) + self.Shell('rm /data/local/tmp/tmp.apk') + if 'Success' not in output: + raise device_errors.AdbCommandFailedError( + cmd, output, device_serial=self._device_serial) + + #override + @property + def is_emulator(self): + return True
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py index e418cdb..373889df 100755 --- a/build/android/incremental_install/installer.py +++ b/build/android/incremental_install/installer.py
@@ -11,6 +11,7 @@ import logging import os import posixpath +import shutil import sys sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir)) @@ -109,7 +110,9 @@ with build_utils.TempDir() as temp_dir: device_lib_dir = posixpath.join(device_incremental_dir, 'lib') for path in native_libs: - os.symlink(path, os.path.join(temp_dir, os.path.basename(path))) + # Note: Can't use symlinks as they don't work when + # "adb push parent_dir" is used (like we do here). + shutil.copy(path, os.path.join(temp_dir, os.path.basename(path))) device.PushChangedFiles([(temp_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) @@ -123,7 +126,7 @@ # Ensure no two files have the same name. transformed_names = _TransformDexPaths(dex_files) for src_path, dest_name in zip(dex_files, transformed_names): - os.symlink(src_path, os.path.join(temp_dir, dest_name)) + shutil.copy(src_path, os.path.join(temp_dir, dest_name)) device.PushChangedFiles([(temp_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False)
diff --git a/build/buildflag_header.gni b/build/buildflag_header.gni index 9054d07..4339996 100644 --- a/build/buildflag_header.gni +++ b/build/buildflag_header.gni
@@ -122,7 +122,7 @@ "--rulename", get_label_info(":$target_name", "label_no_toolchain"), "--gen-dir", - rebase_path(root_gen_dir, root_out_dir), + rebase_path(root_gen_dir, root_build_dir), "--definitions", "{{response_file_name}}", ]
diff --git a/build/common.gypi b/build/common.gypi index 3d12987..4cc1ce4 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -443,7 +443,7 @@ 'mac_want_real_dsym%': 'default', # If this is set, the clang plugins used on the buildbot will be used. - # Run tools/clang/scripts/update.sh to make sure they are compiled. + # Run tools/clang/scripts/update.py to make sure they are compiled. # This causes 'clang_chrome_plugins_flags' to be set. # Has no effect if 'clang' is not set as well. 'clang_use_chrome_plugins%': 1, @@ -847,6 +847,13 @@ 'enable_prod_wallet_service%': 1, }], + # Enable Control Flow Integrity for the official Linux Chrome. + # This triggers an LTO build that requires LLVM Gold plugin to be + # downloaded. See src/tools/clang/scripts/update.sh + ['OS=="linux" and target_arch=="x64" and buildtype=="Official" and branding=="Chrome" and chromeos==0', { + 'cfi_vptr%': 1, + }], + # Enable hotwording on Chrome-branded ChromeOS builds. ['branding=="Chrome" and chromeos==1', { 'enable_hotwording%': 1,
diff --git a/build/config/android/config.gni b/build/config/android/config.gni index 01e1b7a..337b43be 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni
@@ -45,6 +45,12 @@ android_sdk_version = default_android_sdk_version android_sdk_build_tools_version = default_android_sdk_build_tools_version + # Android versionCode for android_apk()s that don't expclitly set one. + android_default_version_code = "1" + + # Android versionName for android_apk()s that don't expclitly set one. + android_default_version_name = "Developer Build" + # The path to the keystore to use for signing builds. android_keystore_path = default_android_keystore_path
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index a1da43ab..f4219f23 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1191,9 +1191,19 @@ # apk_name: Name for final apk. # final_apk_path: Path to final built apk. Default is # $root_out_dir/apks/$apk_name.apk. Setting this will override apk_name. +# loadable_modules: List of paths to native libraries to include. Different +# from |native_libs| in that: +# * dependencies of this .so are not automatically included +# * ".cr.so" is never added +# * they are not side-loaded for _incremental targets. +# * load_library_from_apk, use_chromium_linker, +# and enable_relocation_packing do not apply +# Use this instead of native_libs when you are going to load the library +# conditionally, and only when native_libs doesn't work for you. # native_libs: List paths of native libraries to include in this apk. If these # libraries depend on other shared_library targets, those dependencies will -# also be included in the apk. +# also be included in the apk. When building with is_component_build, +# The extension is automatically changed to ".cr.so". # native_lib_placeholders: List of placeholder filenames to add to the apk # (optional). # apk_under_test: For an instrumentation test apk, this is the target of the @@ -1269,12 +1279,12 @@ _native_libs = [] - _version_code = "1" + _version_code = android_default_version_code if (defined(invoker.version_code)) { _version_code = invoker.version_code } - _version_name = "Developer Build" + _version_name = android_default_version_name if (defined(invoker.version_name)) { _version_name = invoker.version_name } @@ -1627,10 +1637,10 @@ _extra_native_libs = [] _extra_native_libs_deps = [] + _extra_native_libs_even_when_incremental = [] + _extra_native_libs_even_when_incremental_deps = [] + assert(_extra_native_libs_even_when_incremental_deps == []) # Mark as used. if (_native_libs != []) { - _extra_native_libs_even_when_incremental = [] - _extra_native_libs_even_when_incremental_deps = [] - if (is_debug) { _extra_native_libs_even_when_incremental = [ android_gdbserver ] } @@ -1642,6 +1652,9 @@ [ "//base/android/linker:chromium_android_linker" ] } } + if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) { + _extra_native_libs_even_when_incremental += invoker.loadable_modules + } _final_deps += [ ":${_template_name}__create" ] create_apk("${_template_name}__create") { @@ -1692,7 +1705,7 @@ ":$final_dex_target_name", ] - if (_native_libs != [] && !_create_abi_split) { + if ((_native_libs != [] || _extra_native_libs_even_when_incremental != []) && !_create_abi_split) { deps += _native_libs_deps + _extra_native_libs_deps + _extra_native_libs_even_when_incremental_deps + [ _native_libs_file_arg_dep ] @@ -1707,7 +1720,8 @@ } } - if (_native_libs != [] && _create_abi_split) { + if ((_native_libs != [] || _extra_native_libs_even_when_incremental != []) && + _create_abi_split) { _manifest_rule = "${_template_name}__split_manifest_abi_${android_app_abi}" generate_split_manifest(_manifest_rule) { main_manifest = _android_manifest
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 08d10a4..b26f033 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -53,7 +53,7 @@ # TODO(GYP): We should be using 64-bit gold for linking on both 64-bit Linux # and 32-bit linux; 32-bit Gold runs out of address-space on 32-bit builds. # However, something isn't quite working right on the 32-bit builds. - use_gold = is_linux && current_cpu == "x64" + use_gold = is_linux && (current_cpu == "x64" || current_cpu == "arm") # When we are going to use gold we need to find it. # This is initialized below, after use_gold might have been overridden. @@ -303,6 +303,10 @@ # "-Wl,--detect-odr-violations", # ] #} + } else if (linux_use_bundled_binutils) { + # Gold is the default linker for the bundled binutils so we explicitly + # enable the bfd linker when use_gold is not set. + ldflags += [ "-fuse-ld=bfd" ] } if (linux_use_bundled_binutils) { @@ -553,6 +557,7 @@ "-arch", "arm-nonsfi", "--pnacl-bias=arm-nonsfi", + "--target=arm-unknown-nacl", ] ldflags += [ "-arch", @@ -753,6 +758,14 @@ "/wd4459", ] + if (visual_studio_version == "2015") { + # VC++ 2015 changes 32-bit size_t truncation warnings from 4244 to 4267. + # Example: short TruncTest(size_t x) { return x; } + # Since we already disable 4244 we need to disable 4267 during migration. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + cflags += [ "/wd4267" ] + } + # VS xtree header file needs to be patched or 4702 (unreachable code # warning) is reported if _HAS_EXCEPTIONS=0. Disable the warning if xtree is # not patched.
diff --git a/build/config/gcc/BUILD.gn b/build/config/gcc/BUILD.gn index b6ab1d4b..815cfb9 100644 --- a/build/config/gcc/BUILD.gn +++ b/build/config/gcc/BUILD.gn
@@ -29,7 +29,7 @@ ] } else { # Note: Android doesn't support rpath. - rpath_link = "" + rpath_link = "." if (shlib_subdir != ".") { rpath_link = "${shlib_subdir}/" }
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index ddf28f1..a845da53 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chrome_build.gni") + declare_args() { # Compile for Address Sanitizer to find memory bugs. is_asan = false @@ -37,10 +39,6 @@ # https://code.google.com/p/sawbuck/wiki/SyzyASanHowTo is_syzyasan = false - # Compile with Control Flow Integrity to protect virtual calls and casts. - # See http://clang.llvm.org/docs/ControlFlowIntegrity.html - is_cfi = false - # By default, Control Flow Integrity will crash the program if it detects a # violation. Set this to true to print detailed diagnostics instead. use_cfi_diag = false @@ -54,6 +52,11 @@ # declare_args block. User overrides are only applied at the end of a # declare_args block. declare_args() { + # Compile with Control Flow Integrity to protect virtual calls and casts. + # See http://clang.llvm.org/docs/ControlFlowIntegrity.html + is_cfi = is_linux && !is_chromeos && target_cpu == "x64" && + is_chrome_branded && is_official_build + # Use libc++ (buildtools/third_party/libc++ and # buildtools/third_party/libc++abi) instead of stdlibc++ as standard library. # This is intended to be used for instrumented builds.
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn index 313e6090..66c9a06f 100644 --- a/build/toolchain/android/BUILD.gn +++ b/build/toolchain/android/BUILD.gn
@@ -49,6 +49,10 @@ nm = tool_prefix + "nm" strip = "${tool_prefix}strip" + # Don't use .cr.so for loadable_modules since they are always loaded via + # absolute path. + loadable_module_extension = ".so" + toolchain_os = "android" toolchain_cpu = invoker.toolchain_cpu }
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index 43cd780..6742f2b 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -322,7 +322,11 @@ # Use this for {{output_extension}} expansions unless a target manually # overrides it (in which case {{output_extension}} will be what the target # specifies). - default_output_extension = default_shlib_extension + if (defined(invoker.loadable_module_extension)) { + default_output_extension = invoker.loadable_module_extension + } else { + default_output_extension = default_shlib_extension + } output_prefix = "lib"
diff --git a/build_overrides/v8.gni b/build_overrides/v8.gni index b4b933b..e50a6a2 100644 --- a/build_overrides/v8.gni +++ b/build_overrides/v8.gni
@@ -11,9 +11,8 @@ # TODO: Set v8_use_external_startup_data to true on Windows and iOS to match # GYP. -# Windows - http://crbug.com/545641 # iOS - http://crbug.com/545676 -v8_use_external_startup_data = !(is_win || is_ios) +v8_use_external_startup_data = !is_ios # V8 extras # Adding V8 extras files requires API owners review
diff --git a/cc/animation/scrollbar_animation_controller.cc b/cc/animation/scrollbar_animation_controller.cc index 2c11f73..56ed559a 100644 --- a/cc/animation/scrollbar_animation_controller.cc +++ b/cc/animation/scrollbar_animation_controller.cc
@@ -29,9 +29,9 @@ ScrollbarAnimationController::~ScrollbarAnimationController() {} -void ScrollbarAnimationController::Animate(base::TimeTicks now) { +bool ScrollbarAnimationController::Animate(base::TimeTicks now) { if (!is_animating_) - return; + return false; if (last_awaken_time_.is_null()) last_awaken_time_ = now; @@ -41,6 +41,7 @@ if (is_animating_) client_->SetNeedsAnimateForScrollbarAnimation(); + return true; } float ScrollbarAnimationController::AnimationProgressAtTime(
diff --git a/cc/animation/scrollbar_animation_controller.h b/cc/animation/scrollbar_animation_controller.h index 3bb1507..bfc246b 100644 --- a/cc/animation/scrollbar_animation_controller.h +++ b/cc/animation/scrollbar_animation_controller.h
@@ -36,7 +36,7 @@ public: virtual ~ScrollbarAnimationController(); - void Animate(base::TimeTicks now); + bool Animate(base::TimeTicks now); virtual void DidScrollBegin(); virtual void DidScrollUpdate(bool on_resize);
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc index 1c496d9..6b55182 100644 --- a/cc/input/scroll_elasticity_helper.cc +++ b/cc/input/scroll_elasticity_helper.cc
@@ -21,7 +21,7 @@ gfx::ScrollOffset ScrollOffset() const override; gfx::ScrollOffset MaxScrollOffset() const override; void ScrollBy(const gfx::Vector2dF& delta) override; - void RequestAnimate() override; + void RequestOneBeginFrame() override; private: LayerTreeHostImpl* layer_tree_host_impl_; @@ -78,8 +78,8 @@ root_scroll_layer->ScrollBy(delta); } -void ScrollElasticityHelperImpl::RequestAnimate() { - layer_tree_host_impl_->SetNeedsAnimate(); +void ScrollElasticityHelperImpl::RequestOneBeginFrame() { + layer_tree_host_impl_->SetNeedsOneBeginImplFrame(); } // static
diff --git a/cc/input/scroll_elasticity_helper.h b/cc/input/scroll_elasticity_helper.h index a2bdbfe..3ad28fb2c 100644 --- a/cc/input/scroll_elasticity_helper.h +++ b/cc/input/scroll_elasticity_helper.h
@@ -63,9 +63,9 @@ virtual gfx::ScrollOffset MaxScrollOffset() const = 0; virtual void ScrollBy(const gfx::Vector2dF& delta) = 0; - // Request that the controller have its Animate method called for the next - // frame. - virtual void RequestAnimate() = 0; + // Requests that another frame happens for the controller to continue ticking + // animations. + virtual void RequestOneBeginFrame() = 0; }; } // namespace cc
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc index b886e29..92e6926 100644 --- a/cc/layers/picture_image_layer_impl_unittest.cc +++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -24,6 +24,11 @@ public: TestablePictureImageLayerImpl(LayerTreeImpl* tree_impl, int id) : PictureImageLayerImpl(tree_impl, id, false) {} + + scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override { + return make_scoped_ptr(new TestablePictureImageLayerImpl(tree_impl, id())); + } + using PictureLayerImpl::UpdateIdealScales; using PictureLayerImpl::MaximumTilingContentsScale;
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc index 4acd9c1..600805a 100644 --- a/cc/output/direct_renderer.cc +++ b/cc/output/direct_renderer.cc
@@ -205,9 +205,7 @@ DrawingFrame frame; frame.render_passes_in_draw_order = render_passes_in_draw_order; frame.root_render_pass = root_render_pass; - frame.root_damage_rect = Capabilities().using_partial_swap - ? root_render_pass->damage_rect - : root_render_pass->output_rect; + frame.root_damage_rect = root_render_pass->damage_rect; frame.root_damage_rect.Union(overlay_processor_->GetAndResetOverlayDamage()); frame.root_damage_rect.Intersect(gfx::Rect(device_viewport_rect.size())); frame.device_viewport_rect = device_viewport_rect; @@ -226,8 +224,7 @@ if (output_surface_->IsDisplayedAsOverlayPlane()) { // Create the overlay candidate for the output surface, and mark it as - // always - // handled. + // always handled. OverlayCandidate output_surface_plane; output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect); @@ -254,9 +251,18 @@ &frame.ca_layer_overlay_list, &frame.root_damage_rect); } + // The damage rect might be empty now, but if empty swap isn't allowed we + // still have to draw. + bool should_draw = has_copy_requests || !frame.root_damage_rect.IsEmpty() || + !Capabilities().allow_empty_swap; + // If we have to draw but don't support partial swap the whole output should + // be considered damaged. + if (should_draw && !Capabilities().using_partial_swap) + frame.root_damage_rect = root_render_pass->output_rect; + // If all damage is being drawn with overlays or CALayers then skip drawing // the render passes. - if (frame.root_damage_rect.IsEmpty() && !has_copy_requests) { + if (!should_draw) { BindFramebufferToOutputSurface(&frame); } else { for (const auto& pass : *render_passes_in_draw_order) {
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index ea8031e..5c30003e 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -348,6 +348,8 @@ capabilities_.using_partial_swap = settings_->partial_swap_enabled && context_caps.gpu.post_sub_buffer; + capabilities_.allow_empty_swap = capabilities_.using_partial_swap || + context_caps.gpu.commit_overlay_planes; DCHECK(!context_caps.gpu.iosurface || context_caps.gpu.texture_rectangle); @@ -2618,11 +2620,14 @@ gfx::Rect(swap_buffer_rect_.x(), FlippedRootFramebuffer() ? flipped_y_pos_of_rect_bottom : swap_buffer_rect_.y(), - swap_buffer_rect_.width(), - swap_buffer_rect_.height()); + swap_buffer_rect_.width(), swap_buffer_rect_.height()); } else { - compositor_frame.gl_frame_data->sub_buffer_rect = - gfx::Rect(output_surface_->SurfaceSize()); + // Expand the swap rect to the full surface unless it's empty, and empty + // swap is allowed. + if (!swap_buffer_rect_.IsEmpty() || !capabilities_.allow_empty_swap) { + swap_buffer_rect_ = gfx::Rect(surface_size); + } + compositor_frame.gl_frame_data->sub_buffer_rect = swap_buffer_rect_; } output_surface_->SwapBuffers(&compositor_frame);
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index 3430d18..d8b7962 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc
@@ -257,8 +257,8 @@ surface_size_ = size; device_scale_factor_ = scale_factor; if (context_provider_.get()) { - context_provider_->ContextGL()->ResizeCHROMIUM( - size.width(), size.height(), scale_factor); + context_provider_->ContextGL()->ResizeCHROMIUM(size.width(), size.height(), + scale_factor, GL_TRUE); } if (software_device_) software_device_->Resize(size, scale_factor);
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc index 6ee0ac53..5d1b05f 100644 --- a/cc/output/overlay_unittest.cc +++ b/cc/output/overlay_unittest.cc
@@ -23,6 +23,7 @@ #include "cc/test/geometry_test_utils.h" #include "cc/test/test_context_provider.h" #include "cc/test/test_shared_bitmap_manager.h" +#include "cc/test/test_web_graphics_context_3d.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -1744,7 +1745,40 @@ Mock::VerifyAndClearExpectations(&scheduler_); } -TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawn) { +// GLRenderer skips drawing occluded quads when partial swap is enabled. +TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) { + provider_->TestContext3d()->set_have_post_sub_buffer(true); + settings_.partial_swap_enabled = true; + bool use_validator = true; + Init(use_validator); + renderer_->set_expect_overlays(true); + gfx::Rect viewport_rect(16, 16); + + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + CreateFullscreenCandidateQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), + pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + + output_surface_->set_is_displayed_as_overlay_plane(true); + EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(0); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); + SwapBuffers(); + Mock::VerifyAndClearExpectations(renderer_.get()); + Mock::VerifyAndClearExpectations(&scheduler_); +} + +// GLRenderer skips drawing occluded quads when empty swap is enabled. +TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) { + provider_->TestContext3d()->set_have_commit_overlay_planes(true); bool use_validator = true; Init(use_validator); renderer_->set_expect_overlays(true);
diff --git a/cc/output/renderer.h b/cc/output/renderer.h index 82b3ae3..f91b039 100644 --- a/cc/output/renderer.h +++ b/cc/output/renderer.h
@@ -34,6 +34,9 @@ // Capabilities used on compositor thread only. bool using_partial_swap; + // Whether it's valid to SwapBuffers with an empty rect. Trivially true when + // |using_partial_swap|. + bool allow_empty_swap; bool using_egl_image; bool using_image; bool using_discard_framebuffer;
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc index 5b0009a..a1a9cdb 100644 --- a/cc/playback/display_item_list.cc +++ b/cc/playback/display_item_list.cc
@@ -99,6 +99,10 @@ } void DisplayItemList::ToProtobuf(proto::DisplayItemList* proto) { + // The flattened SkPicture approach is going away, and the proto + // doesn't currently support serializing that flattened picture. + DCHECK(retain_individual_display_items_); + RectToProto(layer_rect_, proto->mutable_layer_rect()); settings_.ToProtobuf(proto->mutable_settings());
diff --git a/cc/playback/display_item_list_unittest.cc b/cc/playback/display_item_list_unittest.cc index c2d2b43..b29baa3 100644 --- a/cc/playback/display_item_list_unittest.cc +++ b/cc/playback/display_item_list_unittest.cc
@@ -76,6 +76,8 @@ void ValidateDisplayItemListSerialization(const gfx::Size& layer_size, scoped_refptr<DisplayItemList> list) { + list->Finalize(); + // Serialize and deserialize the DisplayItemList. proto::DisplayItemList proto; list->ToProtobuf(&proto); @@ -83,7 +85,6 @@ DisplayItemList::CreateFromProto(proto); // Finalize the DisplayItemLists to perform raster. - list->Finalize(); new_list->Finalize(); const int pixel_size = 4 * layer_size.GetArea(); @@ -127,7 +128,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -141,7 +141,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -168,7 +167,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -194,7 +192,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -220,7 +217,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -245,7 +241,6 @@ gfx::Size layer_size(10, 10); DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(gfx::Rect(layer_size), settings); @@ -279,7 +274,6 @@ red_paint.setColor(SK_ColorRED); unsigned char pixels[4 * 100 * 100] = {0}; DisplayItemListSettings settings; - settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = DisplayItemList::Create(layer_rect, settings);
diff --git a/cc/raster/bitmap_tile_task_worker_pool.cc b/cc/raster/bitmap_tile_task_worker_pool.cc index 39524ac7..c059483c 100644 --- a/cc/raster/bitmap_tile_task_worker_pool.cc +++ b/cc/raster/bitmap_tile_task_worker_pool.cc
@@ -77,9 +77,7 @@ : task_runner_(task_runner), task_graph_runner_(task_graph_runner), namespace_token_(task_graph_runner->GetNamespaceToken()), - resource_provider_(resource_provider), - task_set_finished_weak_ptr_factory_(this) { -} + resource_provider_(resource_provider) {} BitmapTileTaskWorkerPool::~BitmapTileTaskWorkerPool() { } @@ -88,10 +86,6 @@ return this; } -void BitmapTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { - client_ = client; -} - void BitmapTileTaskWorkerPool::Shutdown() { TRACE_EVENT0("cc", "BitmapTileTaskWorkerPool::Shutdown"); @@ -100,67 +94,11 @@ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); } -void BitmapTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { +void BitmapTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { TRACE_EVENT0("cc", "BitmapTileTaskWorkerPool::ScheduleTasks"); - if (tasks_pending_.none()) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - - // Mark all task sets as pending. - tasks_pending_.set(); - - size_t priority = kTileTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnTaskSetFinished callbacks. - task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets]; - - size_t task_count[kNumberOfTaskSets] = {0}; - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask( - task_runner_.get(), - base::Bind(&BitmapTileTaskWorkerPool::OnTaskSetFinished, - task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set)); - } - - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - const TileTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (!item.task_sets[task_set]) - continue; - - ++task_count[task_set]; - - graph_.edges.push_back( - TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - } - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(), - kTaskSetFinishedTaskPriorityBase + task_set, - task_count[task_set]); - } - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - std::copy(new_task_set_finished_tasks, - new_task_set_finished_tasks + kNumberOfTaskSets, - task_set_finished_tasks_); - - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", - StateAsValue()); + ScheduleTasksOnOriginThread(this, graph); + task_graph_runner_->ScheduleTasks(namespace_token_, graph); } void BitmapTileTaskWorkerPool::CheckForCompletedTasks() { @@ -203,31 +141,4 @@ // Nothing to do here. RasterBufferImpl destructor cleans up after itself. } -void BitmapTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { - TRACE_EVENT1("cc", "BitmapTileTaskWorkerPool::OnTaskSetFinished", "task_set", - task_set); - - DCHECK(tasks_pending_[task_set]); - tasks_pending_[task_set] = false; - if (tasks_pending_.any()) { - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", - "state", StateAsValue()); - } else { - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - } - client_->DidFinishRunningTileTasks(task_set); -} - -scoped_refptr<base::trace_event::ConvertableToTraceFormat> -BitmapTileTaskWorkerPool::StateAsValue() const { - scoped_refptr<base::trace_event::TracedValue> state = - new base::trace_event::TracedValue(); - - state->BeginArray("tasks_pending"); - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) - state->AppendBoolean(tasks_pending_[task_set]); - state->EndArray(); - return state; -} - } // namespace cc
diff --git a/cc/raster/bitmap_tile_task_worker_pool.h b/cc/raster/bitmap_tile_task_worker_pool.h index fe9c4e8..f53768f 100644 --- a/cc/raster/bitmap_tile_task_worker_pool.h +++ b/cc/raster/bitmap_tile_task_worker_pool.h
@@ -5,7 +5,6 @@ #ifndef CC_RASTER_BITMAP_TILE_TASK_WORKER_POOL_H_ #define CC_RASTER_BITMAP_TILE_TASK_WORKER_POOL_H_ -#include "base/memory/weak_ptr.h" #include "base/values.h" #include "cc/raster/tile_task_runner.h" #include "cc/raster/tile_task_worker_pool.h" @@ -34,9 +33,8 @@ TileTaskRunner* AsTileTaskRunner() override; // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override; void Shutdown() override; - void ScheduleTasks(TileTaskQueue* queue) override; + void ScheduleTasks(TaskGraph* graph) override; void CheckForCompletedTasks() override; ResourceFormat GetResourceFormat(bool must_support_alpha) const override; bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; @@ -54,28 +52,16 @@ ResourceProvider* resource_provider); private: - void OnTaskSetFinished(TaskSet task_set); scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue() const; scoped_refptr<base::SequencedTaskRunner> task_runner_; TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; - TileTaskRunnerClient* client_; ResourceProvider* resource_provider_; - TaskSetCollection tasks_pending_; - - scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; Task::Vector completed_tasks_; - base::WeakPtrFactory<BitmapTileTaskWorkerPool> - task_set_finished_weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(BitmapTileTaskWorkerPool); };
diff --git a/cc/raster/gpu_tile_task_worker_pool.cc b/cc/raster/gpu_tile_task_worker_pool.cc index 59c0911..306d5d1 100644 --- a/cc/raster/gpu_tile_task_worker_pool.cc +++ b/cc/raster/gpu_tile_task_worker_pool.cc
@@ -102,10 +102,7 @@ rasterizer_(new GpuRasterizer(context_provider, resource_provider, use_distance_field_text, - gpu_rasterization_msaa_sample_count)), - task_set_finished_weak_ptr_factory_(this), - weak_ptr_factory_(this) { -} + gpu_rasterization_msaa_sample_count)) {} GpuTileTaskWorkerPool::~GpuTileTaskWorkerPool() { DCHECK_EQ(0u, completed_tasks_.size()); @@ -115,10 +112,6 @@ return this; } -void GpuTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { - client_ = client; -} - void GpuTileTaskWorkerPool::Shutdown() { TRACE_EVENT0("cc", "GpuTileTaskWorkerPool::Shutdown"); @@ -127,56 +120,10 @@ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); } -void GpuTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { +void GpuTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { TRACE_EVENT0("cc", "GpuTileTaskWorkerPool::ScheduleTasks"); - // Mark all task sets as pending. - tasks_pending_.set(); - - size_t priority = kTileTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnTaskSetFinished callbacks. - task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets]; - - size_t task_count[kNumberOfTaskSets] = {0}; - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask( - task_runner_.get(), - base::Bind(&GpuTileTaskWorkerPool::OnTaskSetFinished, - task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set)); - } - - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - const TileTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (!item.task_sets[task_set]) - continue; - - ++task_count[task_set]; - - graph_.edges.push_back( - TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - } - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(), - kTaskSetFinishedTaskPriorityBase + task_set, - task_count[task_set]); - } - - ScheduleTasksOnOriginThread(this, &graph_); + ScheduleTasksOnOriginThread(this, graph); // Barrier to sync any new resources to the worker context. rasterizer_->resource_provider() @@ -185,11 +132,7 @@ ->ContextGL() ->OrderingBarrierCHROMIUM(); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - std::copy(new_task_set_finished_tasks, - new_task_set_finished_tasks + kNumberOfTaskSets, - task_set_finished_tasks_); + task_graph_runner_->ScheduleTasks(namespace_token_, graph); } void GpuTileTaskWorkerPool::CheckForCompletedTasks() { @@ -236,13 +179,4 @@ // Nothing to do here. RasterBufferImpl destructor cleans up after itself. } -void GpuTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { - TRACE_EVENT1("cc", "GpuTileTaskWorkerPool::OnTaskSetFinished", "task_set", - task_set); - - DCHECK(tasks_pending_[task_set]); - tasks_pending_[task_set] = false; - client_->DidFinishRunningTileTasks(task_set); -} - } // namespace cc
diff --git a/cc/raster/gpu_tile_task_worker_pool.h b/cc/raster/gpu_tile_task_worker_pool.h index f9ab24c..20ac14c0 100644 --- a/cc/raster/gpu_tile_task_worker_pool.h +++ b/cc/raster/gpu_tile_task_worker_pool.h
@@ -5,7 +5,6 @@ #ifndef CC_RASTER_GPU_TILE_TASK_WORKER_POOL_H_ #define CC_RASTER_GPU_TILE_TASK_WORKER_POOL_H_ -#include "base/memory/weak_ptr.h" #include "cc/raster/tile_task_runner.h" #include "cc/raster/tile_task_worker_pool.h" @@ -32,9 +31,8 @@ TileTaskRunner* AsTileTaskRunner() override; // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override; void Shutdown() override; - void ScheduleTasks(TileTaskQueue* queue) override; + void ScheduleTasks(TaskGraph* graph) override; void CheckForCompletedTasks() override; ResourceFormat GetResourceFormat(bool must_support_alpha) const override; bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; @@ -54,29 +52,15 @@ bool use_distance_field_text, int gpu_rasterization_msaa_sample_count); - void OnTaskSetFinished(TaskSet task_set); void CompleteTasks(const Task::Vector& tasks); scoped_refptr<base::SequencedTaskRunner> task_runner_; TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; - TileTaskRunnerClient* client_; scoped_ptr<GpuRasterizer> rasterizer_; - TaskSetCollection tasks_pending_; - - scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; Task::Vector completed_tasks_; - base::WeakPtrFactory<GpuTileTaskWorkerPool> - task_set_finished_weak_ptr_factory_; - - base::WeakPtrFactory<GpuTileTaskWorkerPool> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(GpuTileTaskWorkerPool); };
diff --git a/cc/raster/one_copy_tile_task_worker_pool.cc b/cc/raster/one_copy_tile_task_worker_pool.cc index c66c2ad5..28677343 100644 --- a/cc/raster/one_copy_tile_task_worker_pool.cc +++ b/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -214,8 +214,7 @@ staging_buffer_expiration_delay_( base::TimeDelta::FromMilliseconds(kStagingBufferExpirationDelayMs)), reduce_memory_usage_pending_(false), - weak_ptr_factory_(this), - task_set_finished_weak_ptr_factory_(this) { + weak_ptr_factory_(this) { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "OneCopyTileTaskWorkerPool", base::ThreadTaskRunnerHandle::Get()); reduce_memory_usage_callback_ = @@ -232,10 +231,6 @@ return this; } -void OneCopyTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { - client_ = client; -} - void OneCopyTileTaskWorkerPool::Shutdown() { TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::Shutdown"); @@ -253,59 +248,10 @@ DCHECK_EQ(free_staging_buffer_usage_in_bytes_, 0); } -void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { +void OneCopyTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks"); - if (tasks_pending_.none()) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - - // Mark all task sets as pending. - tasks_pending_.set(); - - size_t priority = kTileTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnTaskSetFinished callbacks. - task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets]; - - size_t task_count[kNumberOfTaskSets] = {0}; - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask( - task_runner_.get(), - base::Bind(&OneCopyTileTaskWorkerPool::OnTaskSetFinished, - task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set)); - } - - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - const TileTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (!item.task_sets[task_set]) - continue; - - ++task_count[task_set]; - - graph_.edges.push_back( - TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - } - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(), - kTaskSetFinishedTaskPriorityBase + task_set, - task_count[task_set]); - } - - ScheduleTasksOnOriginThread(this, &graph_); + ScheduleTasksOnOriginThread(this, graph); // Barrier to sync any new resources to the worker context. resource_provider_->output_surface() @@ -313,14 +259,7 @@ ->ContextGL() ->OrderingBarrierCHROMIUM(); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - std::copy(new_task_set_finished_tasks, - new_task_set_finished_tasks + kNumberOfTaskSets, - task_set_finished_tasks_); - - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", - StateAsValue()); + task_graph_runner_->ScheduleTasks(namespace_token_, graph); } void OneCopyTileTaskWorkerPool::CheckForCompletedTasks() { @@ -786,47 +725,4 @@ } } -void OneCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { - TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::OnTaskSetFinished", "task_set", - task_set); - - DCHECK(tasks_pending_[task_set]); - tasks_pending_[task_set] = false; - if (tasks_pending_.any()) { - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", - "state", StateAsValue()); - } else { - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - } - client_->DidFinishRunningTileTasks(task_set); -} - -scoped_refptr<base::trace_event::ConvertableToTraceFormat> -OneCopyTileTaskWorkerPool::StateAsValue() const { - scoped_refptr<base::trace_event::TracedValue> state = - new base::trace_event::TracedValue(); - - state->BeginArray("tasks_pending"); - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) - state->AppendBoolean(tasks_pending_[task_set]); - state->EndArray(); - state->BeginDictionary("staging_state"); - StagingStateAsValueInto(state.get()); - state->EndDictionary(); - - return state; -} - -void OneCopyTileTaskWorkerPool::StagingStateAsValueInto( - base::trace_event::TracedValue* staging_state) const { - base::AutoLock lock(lock_); - - staging_state->SetInteger("staging_buffer_count", - static_cast<int>(buffers_.size())); - staging_state->SetInteger("busy_count", - static_cast<int>(busy_buffers_.size())); - staging_state->SetInteger("free_count", - static_cast<int>(free_buffers_.size())); -} - } // namespace cc
diff --git a/cc/raster/one_copy_tile_task_worker_pool.h b/cc/raster/one_copy_tile_task_worker_pool.h index 08445b0..8dc861f 100644 --- a/cc/raster/one_copy_tile_task_worker_pool.h +++ b/cc/raster/one_copy_tile_task_worker_pool.h
@@ -56,9 +56,8 @@ TileTaskRunner* AsTileTaskRunner() override; // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override; void Shutdown() override; - void ScheduleTasks(TileTaskQueue* queue) override; + void ScheduleTasks(TaskGraph* graph) override; void CheckForCompletedTasks() override; ResourceFormat GetResourceFormat(bool must_support_alpha) const override; bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; @@ -127,7 +126,6 @@ void ReduceMemoryUsage(); void ReleaseBuffersNotUsedSince(base::TimeTicks time); - void OnTaskSetFinished(TaskSet task_set); scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue() const; void StagingStateAsValueInto( @@ -136,16 +134,10 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; - TileTaskRunnerClient* client_; ResourceProvider* const resource_provider_; const int max_bytes_per_copy_operation_; const bool use_partial_raster_; - TaskSetCollection tasks_pending_; - scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; Task::Vector completed_tasks_; mutable base::Lock lock_; @@ -165,10 +157,6 @@ base::Closure reduce_memory_usage_callback_; base::WeakPtrFactory<OneCopyTileTaskWorkerPool> weak_ptr_factory_; - // "raster finished" tasks need their own factory as they need to be - // canceled when ScheduleTasks() is called. - base::WeakPtrFactory<OneCopyTileTaskWorkerPool> - task_set_finished_weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(OneCopyTileTaskWorkerPool); };
diff --git a/cc/raster/tile_task_runner.cc b/cc/raster/tile_task_runner.cc index ce568f9..074f045 100644 --- a/cc/raster/tile_task_runner.cc +++ b/cc/raster/tile_task_runner.cc
@@ -4,8 +4,6 @@ #include "cc/raster/tile_task_runner.h" -#include <algorithm> - namespace cc { TileTask::TileTask() : did_schedule_(false), did_complete_(false) { @@ -57,26 +55,4 @@ RasterTask::~RasterTask() { } -TileTaskQueue::Item::Item(RasterTask* task, const TaskSetCollection& task_sets) - : task(task), task_sets(task_sets) { - DCHECK(task_sets.any()); -} - -TileTaskQueue::Item::~Item() { -} - -TileTaskQueue::TileTaskQueue() { -} - -TileTaskQueue::~TileTaskQueue() { -} - -void TileTaskQueue::Swap(TileTaskQueue* other) { - items.swap(other->items); -} - -void TileTaskQueue::Reset() { - items.clear(); -} - } // namespace cc
diff --git a/cc/raster/tile_task_runner.h b/cc/raster/tile_task_runner.h index 103da1fa..1958ca25 100644 --- a/cc/raster/tile_task_runner.h +++ b/cc/raster/tile_task_runner.h
@@ -5,7 +5,6 @@ #ifndef CC_RASTER_TILE_TASK_RUNNER_H_ #define CC_RASTER_TILE_TASK_RUNNER_H_ -#include <bitset> #include <vector> #include "base/callback.h" @@ -76,74 +75,22 @@ ImageDecodeTask::Vector dependencies_; }; -// kNumberOfTaskSets must be greater or equal to the number of values in -// TileManager::NamedTaskSet. -// TODO(reveman): Use template specialization to make it easy for client code to -// check at compile time that the number of supported task sets is correct. -static const size_t kNumberOfTaskSets = 3; -typedef size_t TaskSet; -typedef std::bitset<kNumberOfTaskSets> TaskSetCollection; - -class CC_EXPORT TileTaskRunnerClient { - public: - virtual void DidFinishRunningTileTasks(TaskSet task_set) = 0; - - protected: - virtual ~TileTaskRunnerClient() {} -}; - -struct CC_EXPORT TileTaskQueue { - struct CC_EXPORT Item { - class TaskComparator { - public: - explicit TaskComparator(const RasterTask* task) : task_(task) {} - - bool operator()(const Item& item) const { return item.task == task_; } - - private: - const RasterTask* task_; - }; - - typedef std::vector<Item> Vector; - - Item(RasterTask* task, const TaskSetCollection& task_sets); - ~Item(); - - RasterTask* task; - TaskSetCollection task_sets; - }; - - TileTaskQueue(); - ~TileTaskQueue(); - - void Swap(TileTaskQueue* other); - void Reset(); - - Item::Vector items; -}; - -// This interface can be used to schedule and run tile tasks. The client will -// be notified asynchronously when the set of tasks marked as "required for -// activation" have finished running, when tasks marked "required for draw" -// have finished running, and when all scheduled tasks have finished running. +// This interface can be used to schedule and run tile tasks. // The client can call CheckForCompletedTasks() at any time to dispatch // pending completion callbacks for all tasks that have finished running. class CC_EXPORT TileTaskRunner { public: - // Set the client instance to be notified when finished running tasks. - virtual void SetClient(TileTaskRunnerClient* client) = 0; - // Tells the worker pool to shutdown after canceling all previously scheduled // tasks. Reply callbacks are still guaranteed to run when // CheckForCompletedTasks() is called. virtual void Shutdown() = 0; - // Schedule running of tile tasks in |queue| and all dependencies. - // Previously scheduled tasks that are not in |queue| will be canceled unless + // Schedule running of tile tasks in |graph| and all dependencies. + // Previously scheduled tasks that are not in |graph| will be canceled unless // already running. Once scheduled, reply callbacks are guaranteed to run for // all tasks even if they later get canceled by another call to // ScheduleTasks(). - virtual void ScheduleTasks(TileTaskQueue* queue) = 0; + virtual void ScheduleTasks(TaskGraph* graph) = 0; // Check for completed tasks and dispatch reply callbacks. virtual void CheckForCompletedTasks() = 0;
diff --git a/cc/raster/tile_task_worker_pool.cc b/cc/raster/tile_task_worker_pool.cc index 0ad998c..b55f69d 100644 --- a/cc/raster/tile_task_worker_pool.cc +++ b/cc/raster/tile_task_worker_pool.cc
@@ -4,8 +4,6 @@ #include "cc/raster/tile_task_worker_pool.h" -#include <algorithm> - #include "base/trace_event/trace_event.h" #include "cc/playback/display_list_raster_source.h" #include "skia/ext/refptr.h" @@ -14,66 +12,12 @@ #include "third_party/skia/include/core/SkSurface.h" namespace cc { -namespace { - -class TaskSetFinishedTaskImpl : public TileTask { - public: - explicit TaskSetFinishedTaskImpl( - base::SequencedTaskRunner* task_runner, - const base::Closure& on_task_set_finished_callback) - : task_runner_(task_runner), - on_task_set_finished_callback_(on_task_set_finished_callback) {} - - // Overridden from Task: - void RunOnWorkerThread() override { - TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread"); - TaskSetFinished(); - } - - // Overridden from TileTask: - void ScheduleOnOriginThread(TileTaskClient* client) override {} - void CompleteOnOriginThread(TileTaskClient* client) override {} - - protected: - ~TaskSetFinishedTaskImpl() override {} - - void TaskSetFinished() { - task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_); - } - - private: - scoped_refptr<base::SequencedTaskRunner> task_runner_; - const base::Closure on_task_set_finished_callback_; - - DISALLOW_COPY_AND_ASSIGN(TaskSetFinishedTaskImpl); -}; - -} // namespace - -// This allows a micro benchmark system to run tasks with highest priority, -// since it should finish as quickly as possible. -size_t TileTaskWorkerPool::kBenchmarkTaskPriority = 0u; -// Task priorities that make sure task set finished tasks run before any -// other remaining tasks. This is combined with the task set type to ensure -// proper prioritization ordering between task set types. -size_t TileTaskWorkerPool::kTaskSetFinishedTaskPriorityBase = 1u; -// For correctness, |kTileTaskPriorityBase| must be greater than -// |kTaskSetFinishedTaskPriorityBase + kNumberOfTaskSets|. -size_t TileTaskWorkerPool::kTileTaskPriorityBase = 10u; TileTaskWorkerPool::TileTaskWorkerPool() {} TileTaskWorkerPool::~TileTaskWorkerPool() {} // static -scoped_refptr<TileTask> TileTaskWorkerPool::CreateTaskSetFinishedTask( - base::SequencedTaskRunner* task_runner, - const base::Closure& on_task_set_finished_callback) { - return make_scoped_refptr( - new TaskSetFinishedTaskImpl(task_runner, on_task_set_finished_callback)); -} - -// static void TileTaskWorkerPool::ScheduleTasksOnOriginThread(TileTaskClient* client, TaskGraph* graph) { TRACE_EVENT0("cc", "TileTaskWorkerPool::ScheduleTasksOnOriginThread"); @@ -91,52 +35,6 @@ } } -// static -void TileTaskWorkerPool::InsertNodeForTask(TaskGraph* graph, - TileTask* task, - size_t priority, - size_t dependencies) { - DCHECK(std::find_if(graph->nodes.begin(), graph->nodes.end(), - [task](const TaskGraph::Node& node) { - return node.task == task; - }) == graph->nodes.end()); - graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies)); -} - -// static -void TileTaskWorkerPool::InsertNodesForRasterTask( - TaskGraph* graph, - RasterTask* raster_task, - const ImageDecodeTask::Vector& decode_tasks, - size_t priority) { - size_t dependencies = 0u; - - // Insert image decode tasks. - for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin(); - it != decode_tasks.end(); ++it) { - ImageDecodeTask* decode_task = it->get(); - - // Skip if already decoded. - if (decode_task->HasCompleted()) - continue; - - dependencies++; - - // Add decode task if it doesn't already exists in graph. - TaskGraph::Node::Vector::iterator decode_it = - std::find_if(graph->nodes.begin(), graph->nodes.end(), - [decode_task](const TaskGraph::Node& node) { - return node.task == decode_task; - }); - if (decode_it == graph->nodes.end()) - InsertNodeForTask(graph, decode_task, priority, 0u); - - graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task)); - } - - InsertNodeForTask(graph, raster_task, priority, dependencies); -} - static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) { switch (format) { case RGBA_4444:
diff --git a/cc/raster/tile_task_worker_pool.h b/cc/raster/tile_task_worker_pool.h index 6657b9a..6b550fa2f 100644 --- a/cc/raster/tile_task_worker_pool.h +++ b/cc/raster/tile_task_worker_pool.h
@@ -19,40 +19,14 @@ class CC_EXPORT TileTaskWorkerPool { public: - static size_t kBenchmarkTaskPriority; - static size_t kTaskSetFinishedTaskPriorityBase; - static size_t kTileTaskPriorityBase; - TileTaskWorkerPool(); virtual ~TileTaskWorkerPool(); - // Utility function that can be used to create a "Task set finished" task that - // posts |callback| to |task_runner| when run. - static scoped_refptr<TileTask> CreateTaskSetFinishedTask( - base::SequencedTaskRunner* task_runner, - const base::Closure& callback); - // Utility function that can be used to call ::ScheduleOnOriginThread() for // each task in |graph|. static void ScheduleTasksOnOriginThread(TileTaskClient* client, TaskGraph* graph); - // Utility function that can be used to build a task graph. Inserts a node - // that represents |task| in |graph|. See TaskGraph definition for valid - // |priority| values. - static void InsertNodeForTask(TaskGraph* graph, - TileTask* task, - size_t priority, - size_t dependencies); - - // Utility function that can be used to build a task graph. Inserts nodes that - // represent |task| and all its image decode dependencies in |graph|. - static void InsertNodesForRasterTask( - TaskGraph* graph, - RasterTask* task, - const ImageDecodeTask::Vector& decode_tasks, - size_t priority); - // Utility function that will create a temporary bitmap and copy pixels to // |memory| when necessary. The |canvas_bitmap_rect| is the rect of the bitmap // being played back in the pixel space of the source, ie a rect in the source
diff --git a/cc/raster/tile_task_worker_pool_perftest.cc b/cc/raster/tile_task_worker_pool_perftest.cc index 2bed36d..70902c8 100644 --- a/cc/raster/tile_task_worker_pool_perftest.cc +++ b/cc/raster/tile_task_worker_pool_perftest.cc
@@ -214,15 +214,22 @@ } } - void BuildTileTaskQueue(TileTaskQueue* queue, + void BuildTileTaskGraph(TaskGraph* graph, const RasterTaskVector& raster_tasks) { - for (size_t i = 0u; i < raster_tasks.size(); ++i) { - bool required_for_activation = (i % 2) == 0; - TaskSetCollection task_set_collection; - task_set_collection[ALL] = true; - task_set_collection[REQUIRED_FOR_ACTIVATION] = required_for_activation; - queue->items.push_back( - TileTaskQueue::Item(raster_tasks[i].get(), task_set_collection)); + size_t priority = 0; + + for (auto& raster_task : raster_tasks) { + priority++; + + for (auto& decode_task : raster_task->dependencies()) { + graph->nodes.push_back( + TaskGraph::Node(decode_task.get(), priority, 0u)); + graph->edges.push_back( + TaskGraph::Edge(raster_task.get(), decode_task.get())); + } + + graph->nodes.push_back(TaskGraph::Node( + raster_task.get(), priority, raster_task->dependencies().size())); } } @@ -238,8 +245,7 @@ class TileTaskWorkerPoolPerfTest : public TileTaskWorkerPoolPerfTestBase, - public testing::TestWithParam<TileTaskWorkerPoolType>, - public TileTaskRunnerClient { + public testing::TestWithParam<TileTaskWorkerPoolType> { public: // Overridden from testing::Test: void SetUp() override { @@ -273,18 +279,12 @@ } DCHECK(tile_task_worker_pool_); - tile_task_worker_pool_->AsTileTaskRunner()->SetClient(this); } void TearDown() override { tile_task_worker_pool_->AsTileTaskRunner()->Shutdown(); tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); } - // Overriden from TileTaskRunnerClient: - void DidFinishRunningTileTasks(TaskSet task_set) override { - tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); - } - void RunMessageLoopUntilAllTasksHaveCompleted() { task_graph_runner_->RunUntilIdle(); task_runner_->RunUntilIdle(); @@ -298,19 +298,19 @@ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks); CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks); - // Avoid unnecessary heap allocations by reusing the same queue. - TileTaskQueue queue; + // Avoid unnecessary heap allocations by reusing the same graph. + TaskGraph graph; timer_.Reset(); do { - queue.Reset(); - BuildTileTaskQueue(&queue, raster_tasks); - tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue); + graph.Reset(); + BuildTileTaskGraph(&graph, raster_tasks); + tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&graph); tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - TileTaskQueue empty; + TaskGraph empty; tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty); RunMessageLoopUntilAllTasksHaveCompleted(); @@ -330,21 +330,21 @@ &raster_tasks[i]); } - // Avoid unnecessary heap allocations by reusing the same queue. - TileTaskQueue queue; + // Avoid unnecessary heap allocations by reusing the same graph. + TaskGraph graph; size_t count = 0; timer_.Reset(); do { - queue.Reset(); - BuildTileTaskQueue(&queue, raster_tasks[count % kNumVersions]); - tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue); + graph.Reset(); + BuildTileTaskGraph(&graph, raster_tasks[count % kNumVersions]); + tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&graph); tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); ++count; timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - TileTaskQueue empty; + TaskGraph empty; tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty); RunMessageLoopUntilAllTasksHaveCompleted(); @@ -360,19 +360,19 @@ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks); CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks); - // Avoid unnecessary heap allocations by reusing the same queue. - TileTaskQueue queue; + // Avoid unnecessary heap allocations by reusing the same graph. + TaskGraph graph; timer_.Reset(); do { - queue.Reset(); - BuildTileTaskQueue(&queue, raster_tasks); - tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue); + graph.Reset(); + BuildTileTaskGraph(&graph, raster_tasks); + tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&graph); RunMessageLoopUntilAllTasksHaveCompleted(); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - TileTaskQueue empty; + TaskGraph empty; tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty); RunMessageLoopUntilAllTasksHaveCompleted(); @@ -461,7 +461,7 @@ FakeResourceProvider::Create(output_surface_.get(), nullptr); } - void RunBuildTileTaskQueueTest(const std::string& test_name, + void RunBuildTileTaskGraphTest(const std::string& test_name, unsigned num_raster_tasks, unsigned num_image_decode_tasks) { ImageDecodeTask::Vector image_decode_tasks; @@ -469,28 +469,28 @@ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks); CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks); - // Avoid unnecessary heap allocations by reusing the same queue. - TileTaskQueue queue; + // Avoid unnecessary heap allocations by reusing the same graph. + TaskGraph graph; timer_.Reset(); do { - queue.Reset(); - BuildTileTaskQueue(&queue, raster_tasks); + graph.Reset(); + BuildTileTaskGraph(&graph, raster_tasks); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); - perf_test::PrintResult("build_raster_task_queue", "", test_name, + perf_test::PrintResult("build_raster_task_graph", "", test_name, timer_.LapsPerSecond(), "runs/s", true); } }; -TEST_F(TileTaskWorkerPoolCommonPerfTest, BuildTileTaskQueue) { - RunBuildTileTaskQueueTest("1_0", 1, 0); - RunBuildTileTaskQueueTest("32_0", 32, 0); - RunBuildTileTaskQueueTest("1_1", 1, 1); - RunBuildTileTaskQueueTest("32_1", 32, 1); - RunBuildTileTaskQueueTest("1_4", 1, 4); - RunBuildTileTaskQueueTest("32_4", 32, 4); +TEST_F(TileTaskWorkerPoolCommonPerfTest, BuildTileTaskGraph) { + RunBuildTileTaskGraphTest("1_0", 1, 0); + RunBuildTileTaskGraphTest("32_0", 32, 0); + RunBuildTileTaskGraphTest("1_1", 1, 1); + RunBuildTileTaskGraphTest("32_1", 32, 1); + RunBuildTileTaskGraphTest("1_4", 1, 4); + RunBuildTileTaskGraphTest("32_4", 32, 4); } } // namespace
diff --git a/cc/raster/tile_task_worker_pool_unittest.cc b/cc/raster/tile_task_worker_pool_unittest.cc index aff1423..62239c16 100644 --- a/cc/raster/tile_task_worker_pool_unittest.cc +++ b/cc/raster/tile_task_worker_pool_unittest.cc
@@ -4,6 +4,7 @@ #include "cc/raster/tile_task_worker_pool.h" +#include <algorithm> #include <limits> #include <vector> @@ -17,6 +18,7 @@ #include "cc/raster/gpu_tile_task_worker_pool.h" #include "cc/raster/one_copy_tile_task_worker_pool.h" #include "cc/raster/raster_buffer.h" +#include "cc/raster/synchronous_task_graph_runner.h" #include "cc/raster/tile_task_runner.h" #include "cc/raster/zero_copy_tile_task_worker_pool.h" #include "cc/resources/resource_pool.h" @@ -28,7 +30,6 @@ #include "cc/test/fake_resource_provider.h" #include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_shared_bitmap_manager.h" -#include "cc/test/test_task_graph_runner.h" #include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gtest/include/gtest/gtest.h" @@ -116,8 +117,7 @@ }; class TileTaskWorkerPoolTest - : public testing::TestWithParam<TileTaskWorkerPoolType>, - public TileTaskRunnerClient { + : public testing::TestWithParam<TileTaskWorkerPoolType> { public: struct RasterTaskResult { unsigned id; @@ -170,7 +170,6 @@ } DCHECK(tile_task_worker_pool_); - tile_task_worker_pool_->AsTileTaskRunner()->SetClient(this); } void TearDown() override { @@ -183,46 +182,22 @@ base::MessageLoop::current()->QuitWhenIdle(); } - // Overriden from TileTaskWorkerPoolClient: - void DidFinishRunningTileTasks(TaskSet task_set) override { - EXPECT_FALSE(completed_task_sets_[task_set]); - completed_task_sets_[task_set] = true; - if (task_set == ALL) { - EXPECT_TRUE((~completed_task_sets_).none()); - all_tile_tasks_finished_.Schedule(); - } - } - void RunMessageLoopUntilAllTasksHaveCompleted() { - if (timeout_seconds_) { - timeout_.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout, - base::Unretained(this))); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, timeout_.callback(), - base::TimeDelta::FromSeconds(timeout_seconds_)); - } - - base::MessageLoop::current()->Run(); - - timeout_.Cancel(); - - ASSERT_FALSE(timed_out_) << "Test timed out"; + task_graph_runner_.RunUntilIdle(); + tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); } void ScheduleTasks() { - TileTaskQueue queue; + graph_.Reset(); + + size_t priority = 0; for (RasterTaskVector::const_iterator it = tasks_.begin(); it != tasks_.end(); ++it) { - TaskSetCollection task_sets; - task_sets[REQUIRED_FOR_ACTIVATION] = true; - task_sets[REQUIRED_FOR_DRAW] = true; - task_sets[ALL] = true; - queue.items.push_back(TileTaskQueue::Item(it->get(), task_sets)); + graph_.nodes.emplace_back(it->get(), priority++, 0 /* dependencies */); } - completed_task_sets_.reset(); - tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue); + tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&graph_); } void AppendTask(unsigned id, const gfx::Size& size) { @@ -315,14 +290,14 @@ scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_; TestGpuMemoryBufferManager gpu_memory_buffer_manager_; TestSharedBitmapManager shared_bitmap_manager_; - TestTaskGraphRunner task_graph_runner_; + SynchronousTaskGraphRunner task_graph_runner_; base::CancelableClosure timeout_; UniqueNotifier all_tile_tasks_finished_; int timeout_seconds_; bool timed_out_; RasterTaskVector tasks_; std::vector<RasterTaskResult> completed_tasks_; - TaskSetCollection completed_task_sets_; + TaskGraph graph_; }; TEST_P(TileTaskWorkerPoolTest, Basic) { @@ -391,21 +366,6 @@ EXPECT_FALSE(completed_tasks()[1].canceled); } -TEST_P(TileTaskWorkerPoolTest, ScheduleEmptyStillTriggersCallback) { - // Don't append any tasks, just call ScheduleTasks. - ScheduleTasks(); - - EXPECT_FALSE(completed_task_sets_[REQUIRED_FOR_ACTIVATION]); - EXPECT_FALSE(completed_task_sets_[REQUIRED_FOR_DRAW]); - EXPECT_FALSE(completed_task_sets_[ALL]); - - RunMessageLoopUntilAllTasksHaveCompleted(); - - EXPECT_TRUE(completed_task_sets_[REQUIRED_FOR_ACTIVATION]); - EXPECT_TRUE(completed_task_sets_[REQUIRED_FOR_DRAW]); - EXPECT_TRUE(completed_task_sets_[ALL]); -} - INSTANTIATE_TEST_CASE_P(TileTaskWorkerPoolTests, TileTaskWorkerPoolTest, ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
diff --git a/cc/raster/zero_copy_tile_task_worker_pool.cc b/cc/raster/zero_copy_tile_task_worker_pool.cc index 147eeca..8830c1f02 100644 --- a/cc/raster/zero_copy_tile_task_worker_pool.cc +++ b/cc/raster/zero_copy_tile_task_worker_pool.cc
@@ -80,8 +80,7 @@ task_graph_runner_(task_graph_runner), namespace_token_(task_graph_runner->GetNamespaceToken()), resource_provider_(resource_provider), - use_rgba_4444_texture_format_(use_rgba_4444_texture_format), - task_set_finished_weak_ptr_factory_(this) {} + use_rgba_4444_texture_format_(use_rgba_4444_texture_format) {} ZeroCopyTileTaskWorkerPool::~ZeroCopyTileTaskWorkerPool() { } @@ -90,10 +89,6 @@ return this; } -void ZeroCopyTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { - client_ = client; -} - void ZeroCopyTileTaskWorkerPool::Shutdown() { TRACE_EVENT0("cc", "ZeroCopyTileTaskWorkerPool::Shutdown"); @@ -102,67 +97,11 @@ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); } -void ZeroCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { +void ZeroCopyTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { TRACE_EVENT0("cc", "ZeroCopyTileTaskWorkerPool::ScheduleTasks"); - if (tasks_pending_.none()) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); - - // Mark all task sets as pending. - tasks_pending_.set(); - - size_t priority = kTileTaskPriorityBase; - - graph_.Reset(); - - // Cancel existing OnTaskSetFinished callbacks. - task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets]; - - size_t task_count[kNumberOfTaskSets] = {0}; - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask( - task_runner_.get(), - base::Bind(&ZeroCopyTileTaskWorkerPool::OnTaskSetFinished, - task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set)); - } - - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - const TileTaskQueue::Item& item = *it; - RasterTask* task = item.task; - DCHECK(!task->HasCompleted()); - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (!item.task_sets[task_set]) - continue; - - ++task_count[task_set]; - - graph_.edges.push_back( - TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get())); - } - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - } - - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(), - kTaskSetFinishedTaskPriorityBase + task_set, - task_count[task_set]); - } - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - std::copy(new_task_set_finished_tasks, - new_task_set_finished_tasks + kNumberOfTaskSets, - task_set_finished_tasks_); - - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", - StateAsValue()); + ScheduleTasksOnOriginThread(this, graph); + task_graph_runner_->ScheduleTasks(namespace_token_, graph); } void ZeroCopyTileTaskWorkerPool::CheckForCompletedTasks() { @@ -207,31 +146,4 @@ // Nothing to do here. RasterBufferImpl destructor cleans up after itself. } -void ZeroCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { - TRACE_EVENT1("cc", "ZeroCopyTileTaskWorkerPool::OnTaskSetFinished", - "task_set", task_set); - - DCHECK(tasks_pending_[task_set]); - tasks_pending_[task_set] = false; - if (tasks_pending_.any()) { - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", - "state", StateAsValue()); - } else { - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - } - client_->DidFinishRunningTileTasks(task_set); -} - -scoped_refptr<base::trace_event::ConvertableToTraceFormat> -ZeroCopyTileTaskWorkerPool::StateAsValue() const { - scoped_refptr<base::trace_event::TracedValue> state = - new base::trace_event::TracedValue(); - - state->BeginArray("tasks_pending"); - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) - state->AppendBoolean(tasks_pending_[task_set]); - state->EndArray(); - return state; -} - } // namespace cc
diff --git a/cc/raster/zero_copy_tile_task_worker_pool.h b/cc/raster/zero_copy_tile_task_worker_pool.h index b101559..3ca9b06 100644 --- a/cc/raster/zero_copy_tile_task_worker_pool.h +++ b/cc/raster/zero_copy_tile_task_worker_pool.h
@@ -35,9 +35,8 @@ TileTaskRunner* AsTileTaskRunner() override; // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override; void Shutdown() override; - void ScheduleTasks(TileTaskQueue* queue) override; + void ScheduleTasks(TaskGraph* graph) override; void CheckForCompletedTasks() override; ResourceFormat GetResourceFormat(bool must_support_alpha) const override; bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; @@ -56,30 +55,18 @@ bool use_rgba_4444_texture_format); private: - void OnTaskSetFinished(TaskSet task_set); scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue() const; scoped_refptr<base::SequencedTaskRunner> task_runner_; TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; - TileTaskRunnerClient* client_; ResourceProvider* resource_provider_; bool use_rgba_4444_texture_format_; - TaskSetCollection tasks_pending_; - - scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; - - // Task graph used when scheduling tasks and vector used to gather - // completed tasks. - TaskGraph graph_; Task::Vector completed_tasks_; - base::WeakPtrFactory<ZeroCopyTileTaskWorkerPool> - task_set_finished_weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ZeroCopyTileTaskWorkerPool); };
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 1c840a4..6823c69 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -182,11 +182,6 @@ ProcessScheduledActions(); } -void Scheduler::SetNeedsAnimate() { - state_machine_.SetNeedsAnimate(); - ProcessScheduledActions(); -} - void Scheduler::SetNeedsPrepareTiles() { DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_PREPARE_TILES)); state_machine_.SetNeedsPrepareTiles(); @@ -708,10 +703,6 @@ switch (action) { case SchedulerStateMachine::ACTION_NONE: break; - case SchedulerStateMachine::ACTION_ANIMATE: - state_machine_.WillAnimate(); - client_->ScheduledActionAnimate(); - break; case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: compositor_timing_history_->WillBeginMainFrame( begin_main_frame_args_.on_critical_path);
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index dbccd5f..afd5a72 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -40,7 +40,6 @@ const BeginFrameArgs& args) = 0; virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0; virtual DrawResult ScheduledActionDrawAndSwapForced() = 0; - virtual void ScheduledActionAnimate() = 0; virtual void ScheduledActionCommit() = 0; virtual void ScheduledActionActivateSyncTree() = 0; virtual void ScheduledActionBeginOutputSurfaceCreation() = 0; @@ -92,8 +91,6 @@ void SetNeedsRedraw(); - void SetNeedsAnimate(); - void SetNeedsPrepareTiles(); void DidSwapBuffers();
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index eedc6c3..333b8edf 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -26,12 +26,10 @@ forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), commit_count_(0), current_frame_number_(0), - last_frame_number_animate_performed_(-1), last_frame_number_swap_performed_(-1), last_frame_number_draw_performed_(-1), last_frame_number_begin_main_frame_sent_(-1), last_frame_number_invalidate_output_surface_performed_(-1), - animate_funnel_(false), draw_funnel_(false), send_begin_main_frame_funnel_(true), invalidate_output_surface_funnel_(false), @@ -40,7 +38,6 @@ pending_swaps_(0), swaps_with_current_output_surface_(0), needs_redraw_(false), - needs_animate_(false), needs_prepare_tiles_(false), needs_begin_main_frame_(false), needs_one_begin_impl_frame_(false), @@ -168,8 +165,6 @@ switch (action) { case ACTION_NONE: return "ACTION_NONE"; - case ACTION_ANIMATE: - return "ACTION_ANIMATE"; case ACTION_SEND_BEGIN_MAIN_FRAME: return "ACTION_SEND_BEGIN_MAIN_FRAME"; case ACTION_COMMIT: @@ -218,15 +213,12 @@ state->BeginDictionary("minor_state"); state->SetInteger("commit_count", commit_count_); state->SetInteger("current_frame_number", current_frame_number_); - state->SetInteger("last_frame_number_animate_performed", - last_frame_number_animate_performed_); state->SetInteger("last_frame_number_swap_performed", last_frame_number_swap_performed_); state->SetInteger("last_frame_number_draw_performed", last_frame_number_draw_performed_); state->SetInteger("last_frame_number_begin_main_frame_sent", last_frame_number_begin_main_frame_sent_); - state->SetBoolean("funnel: animate_funnel", animate_funnel_); state->SetBoolean("funnel: draw_funnel", draw_funnel_); state->SetBoolean("funnel: send_begin_main_frame_funnel", send_begin_main_frame_funnel_); @@ -239,7 +231,6 @@ state->SetInteger("swaps_with_current_output_surface", swaps_with_current_output_surface_); state->SetBoolean("needs_redraw", needs_redraw_); - state->SetBoolean("needs_animate_", needs_animate_); state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); state->SetBoolean("needs_one_begin_impl_frame", needs_one_begin_impl_frame_); @@ -390,22 +381,6 @@ return pending_tree_is_ready_for_activation_; } -bool SchedulerStateMachine::ShouldAnimate() const { - // Do not animate too many times in a single frame. - if (animate_funnel_) - return false; - - // Don't animate if we are waiting on the first commit after a surface. - if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) - return false; - - if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING && - begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) - return false; - - return needs_redraw_ || needs_animate_; -} - bool SchedulerStateMachine::CouldSendBeginMainFrame() const { if (!needs_begin_main_frame_) return false; @@ -557,8 +532,6 @@ return ACTION_ACTIVATE_SYNC_TREE; if (ShouldCommit()) return ACTION_COMMIT; - if (ShouldAnimate()) - return ACTION_ANIMATE; if (ShouldDraw()) { if (PendingDrawsShouldBeAborted()) return ACTION_DRAW_AND_SWAP_ABORT; @@ -578,13 +551,6 @@ return ACTION_NONE; } -void SchedulerStateMachine::WillAnimate() { - DCHECK(!animate_funnel_); - last_frame_number_animate_performed_ = current_frame_number_; - animate_funnel_ = true; - needs_animate_ = false; -} - void SchedulerStateMachine::WillSendBeginMainFrame() { DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); DCHECK(visible_); @@ -598,10 +564,6 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) { commit_count_++; - // Animate after commit even if we've already animated. - if (!commit_has_no_updates) - animate_funnel_ = false; - if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; } else { @@ -817,7 +779,7 @@ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) return true; - return needs_animate_ || needs_redraw_ || needs_one_begin_impl_frame_ || + return needs_redraw_ || needs_one_begin_impl_frame_ || (needs_begin_main_frame_ && !defer_commits_); } @@ -877,7 +839,6 @@ needs_one_begin_impl_frame_ = false; // Clear funnels for any actions we perform during the frame. - animate_funnel_ = false; send_begin_main_frame_funnel_ = false; invalidate_output_surface_funnel_ = false; @@ -1008,13 +969,8 @@ void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; } -void SchedulerStateMachine::SetNeedsAnimate() { - needs_animate_ = true; -} - bool SchedulerStateMachine::OnlyImplSideUpdatesExpected() const { - bool has_impl_updates = - needs_redraw_ || needs_animate_ || needs_one_begin_impl_frame_; + bool has_impl_updates = needs_redraw_ || needs_one_begin_impl_frame_; bool main_updates_expected = needs_begin_main_frame_ || begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE ||
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 93f6766..2cc4c63 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -117,7 +117,6 @@ enum Action { ACTION_NONE, - ACTION_ANIMATE, ACTION_SEND_BEGIN_MAIN_FRAME, ACTION_COMMIT, ACTION_ACTIVATE_SYNC_TREE, @@ -134,7 +133,6 @@ void AsValueInto(base::trace_event::TracedValue* dict) const; Action NextAction() const; - void WillAnimate(); void WillSendBeginMainFrame(); void WillCommit(bool commit_had_no_updates); void WillActivate(); @@ -181,9 +179,6 @@ void SetNeedsRedraw(); bool needs_redraw() const { return needs_redraw_; } - void SetNeedsAnimate(); - bool needs_animate() const { return needs_animate_; } - bool OnlyImplSideUpdatesExpected() const; // Indicates that prepare-tiles is required. This guarantees another @@ -295,7 +290,6 @@ // TODO(brianderson): Remove this once NPAPI support is removed. bool SendingBeginMainFrameMightCauseDeadlock() const; - bool ShouldAnimate() const; bool ShouldBeginOutputSurfaceCreation() const; bool ShouldDraw() const; bool ShouldActivatePendingTree() const; @@ -317,7 +311,6 @@ // These are used for tracing only. int commit_count_; int current_frame_number_; - int last_frame_number_animate_performed_; int last_frame_number_swap_performed_; int last_frame_number_draw_performed_; int last_frame_number_begin_main_frame_sent_; @@ -325,7 +318,6 @@ // These are used to ensure that an action only happens once per frame, // deadline, etc. - bool animate_funnel_; bool draw_funnel_; bool send_begin_main_frame_funnel_; bool invalidate_output_surface_funnel_; @@ -340,7 +332,6 @@ int pending_swaps_; int swaps_with_current_output_surface_; bool needs_redraw_; - bool needs_animate_; bool needs_prepare_tiles_; bool needs_begin_main_frame_; bool needs_one_begin_impl_frame_;
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index e6adbc6..8999b2f 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -14,7 +14,7 @@ // Value of: actual() Actual: 7 // Expected: expected() Which is: 0 // With: -// Value of: actual() Actual: "ACTION_ANIMATE" +// Value of: actual() Actual: "ACTION_DRAW_AND_SWAP" // Expected: expected() Which is: "ACTION_NONE" #define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \ EXPECT_STREQ(SchedulerStateMachine::enum_tostring(expected), \ @@ -117,8 +117,8 @@ bool NeedsCommit() const { return needs_begin_main_frame_; } - void SetNeedsAnimateForTest(bool needs_animate) { - needs_animate_ = needs_animate; + void SetNeedsOneBeginImplFrame(bool needs_frame) { + needs_one_begin_impl_frame_ = needs_frame; } void SetNeedsRedraw(bool needs_redraw) { needs_redraw_ = needs_redraw; } @@ -168,10 +168,6 @@ sm->WillActivate(); return; - case SchedulerStateMachine::ACTION_ANIMATE: - sm->WillAnimate(); - return; - case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: sm->WillSendBeginMainFrame(); return; @@ -221,25 +217,30 @@ // Don't request BeginFrames if we are idle. state.SetNeedsRedraw(false); - state.SetNeedsAnimateForTest(false); + state.SetNeedsOneBeginImplFrame(false); EXPECT_FALSE(state.BeginFrameNeeded()); + // Request BeginFrames if we one is needed. + state.SetNeedsRedraw(false); + state.SetNeedsOneBeginImplFrame(true); + EXPECT_TRUE(state.BeginFrameNeeded()); + // Request BeginFrames if we are ready to draw. state.SetVisible(true); state.SetNeedsRedraw(true); - state.SetNeedsAnimateForTest(false); + state.SetNeedsOneBeginImplFrame(false); EXPECT_TRUE(state.BeginFrameNeeded()); // Don't background tick for needs_redraw. state.SetVisible(false); state.SetNeedsRedraw(true); - state.SetNeedsAnimateForTest(false); + state.SetNeedsOneBeginImplFrame(false); EXPECT_FALSE(state.BeginFrameNeeded()); // Proactively request BeginFrames when commit is pending. state.SetVisible(true); state.SetNeedsRedraw(false); - state.SetNeedsAnimateForTest(false); + state.SetNeedsOneBeginImplFrame(false); state.SetNeedsBeginMainFrameForTest(true); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -247,7 +248,7 @@ // we are currently deferring commits. state.SetVisible(true); state.SetNeedsRedraw(false); - state.SetNeedsAnimateForTest(false); + state.SetNeedsOneBeginImplFrame(false); state.SetNeedsBeginMainFrameForTest(true); state.SetDeferCommits(true); EXPECT_FALSE(state.BeginFrameNeeded()); @@ -403,7 +404,6 @@ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); @@ -423,7 +423,6 @@ // Start a frame. state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -445,7 +444,6 @@ EXPECT_TRUE(state.CommitPending()); EXPECT_TRUE(state.RedrawPending()); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -468,7 +466,6 @@ // Start a frame. state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -510,7 +507,6 @@ // Verify we draw with the new frame. state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -543,7 +539,6 @@ // Then initiate a draw that fails. state.SetNeedsRedraw(true); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -568,7 +563,6 @@ // The redraw should be forced at the end of the next BeginImplFrame. state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -602,7 +596,6 @@ // Then initiate a draw. state.SetNeedsRedraw(true); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -610,7 +603,6 @@ for (int i = 0; i < draw_limit; ++i) { state.SetNeedsRedraw(true); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -646,7 +638,6 @@ for (int i = 0; i < draw_limit; ++i) { state.SetNeedsRedraw(true); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -672,7 +663,6 @@ state.SetNeedsRedraw(true); EXPECT_TRUE(state.BeginFrameNeeded()); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_TRUE(state.RedrawPending()); @@ -689,7 +679,6 @@ // We should not be trying to draw again now, but we have a commit pending. EXPECT_TRUE(state.BeginFrameNeeded()); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // We should try to draw again at the end of the next BeginImplFrame on @@ -712,7 +701,6 @@ // Draw the first frame. EXPECT_TRUE(state.BeginFrameNeeded()); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -730,10 +718,7 @@ // Move to another frame. This should now draw. EXPECT_TRUE(state.BeginFrameNeeded()); state.OnBeginImplFrame(); - - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -805,7 +790,6 @@ expected_action = SchedulerStateMachine::ACTION_COMMIT; } else { expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE; - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); } // Case 1: needs_begin_main_frame=false. @@ -896,7 +880,6 @@ state.SetNeedsRedraw(true); state.SetCanDraw(false); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -907,7 +890,6 @@ state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -965,7 +947,6 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); state.NotifyReadyToActivate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1016,7 +997,6 @@ // At BeginImplFrame deadline, draw. state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); @@ -1051,7 +1031,6 @@ // begin frame and commit it. state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); state.NotifyBeginMainFrameStarted(); @@ -1082,7 +1061,6 @@ // active tree, we will not do so. state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -1121,7 +1099,6 @@ state.SetNeedsRedraw(true); state.SetNeedsBeginMainFrame(); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1144,13 +1121,11 @@ // Swap throttled. Do not draw. state.DidSwapBuffers(); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.DidSwapBuffersComplete(); // Haven't draw since last commit, do not begin new main frame. state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // At BeginImplFrame deadline, draw. This draws unblocks BeginMainFrame. @@ -1205,7 +1180,6 @@ // At BeginImplFrame deadline, draw. state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); @@ -1452,7 +1426,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); - // Until that commit finishes, we shouldn't be drawing or animate. + // Until that commit finishes, we shouldn't be drawing. state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1472,7 +1446,6 @@ // automatically cause a redraw. EXPECT_TRUE(state.RedrawPending()); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( @@ -1490,7 +1463,6 @@ // SetCanDraw if waiting on first draw after activate. state.SetNeedsRedraw(true); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -1506,7 +1478,6 @@ state.SetNeedsRedraw(true); state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1521,7 +1492,6 @@ EXPECT_TRUE(state.needs_redraw()); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.SetCanDraw(false); EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); @@ -1540,7 +1510,6 @@ // Set damage and expect a draw. state.SetNeedsRedraw(true); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1603,7 +1572,6 @@ // Set damage and expect a draw. state.SetNeedsRedraw(true); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1670,7 +1638,6 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); @@ -1885,7 +1852,6 @@ state.SetNeedsBeginMainFrame(); // We should start the commit normally. - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1914,7 +1880,6 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); @@ -1934,7 +1899,6 @@ state.SetNeedsRedraw(true); state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -2017,120 +1981,6 @@ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); } -TEST(SchedulerStateMachineTest, TestSetNeedsAnimateWithDraw) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - - // Test requesting an animation that, when run, causes us to draw. - state.SetNeedsAnimate(); - EXPECT_TRUE(state.BeginFrameNeeded()); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - - // The animation will request draw if it ticks anything. - state.SetNeedsRedraw(true); - - state.OnBeginImplFrameDeadlinePending(); - state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); -} - -TEST(SchedulerStateMachineTest, TestSetNeedsAnimateWithoutDraw) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - - // Test requesting an animation but not changing anything won't draw. - state.SetNeedsAnimate(); - EXPECT_TRUE(state.BeginFrameNeeded()); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - - // The animation does not do anything, so no draw is rquested. - - state.OnBeginImplFrameDeadlinePending(); - state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); -} - -TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - - // Check that animations are updated before we start a commit. - state.SetNeedsAnimate(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.SetNeedsBeginMainFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_TRUE(state.BeginFrameNeeded()); - - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); -} - -TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - - // Check that animations are updated before we start a commit. - state.SetNeedsAnimate(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.SetNeedsBeginMainFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_TRUE(state.BeginFrameNeeded()); - - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - - state.NotifyBeginMainFrameStarted(); - state.NotifyReadyToCommit(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); - - // Set the redraw bit before the animate step so we can verify ordering, - // which mimics a redraw caused by something other than the animation itself. - state.SetNeedsRedraw(true); - - state.OnBeginImplFrameDeadlinePending(); - state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); -} - -TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - - // Test requesting an animation after we have already animated during this - // frame. - state.SetNeedsRedraw(true); - EXPECT_TRUE(state.BeginFrameNeeded()); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - - state.SetNeedsAnimate(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - - state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); -} - TEST(SchedulerStateMachineTest, TestForwardBeginFramesToChildren) { SchedulerSettings settings; StateMachine state(settings);
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index f8f2e8e..f041f7f 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -59,8 +59,7 @@ void Reset() { actions_.clear(); states_.clear(); - animate_causes_redraw_ = false; - animate_causes_animate_ = false; + will_begin_impl_frame_causes_redraw_ = false; will_begin_impl_frame_requests_one_begin_impl_frame_ = false; draw_will_happen_ = true; swap_will_happen_if_draw_happens_ = true; @@ -96,11 +95,8 @@ void SetWillBeginImplFrameRequestsOneBeginImplFrame(bool request) { will_begin_impl_frame_requests_one_begin_impl_frame_ = request; } - void SetAnimateCausesRedraw(bool animate_causes_redraw) { - animate_causes_redraw_ = animate_causes_redraw; - } - void SetAnimateCausesAnimate(bool animate_causes_animate) { - animate_causes_animate_ = animate_causes_animate; + void SetWillBeginImplFrameCausesRedraw(bool causes_redraw) { + will_begin_impl_frame_causes_redraw_ = causes_redraw; } void SetDrawWillHappen(bool draw_will_happen) { draw_will_happen_ = draw_will_happen; @@ -116,6 +112,8 @@ PushAction("WillBeginImplFrame"); if (will_begin_impl_frame_requests_one_begin_impl_frame_) scheduler_->SetNeedsOneBeginImplFrame(); + if (will_begin_impl_frame_causes_redraw_) + scheduler_->SetNeedsRedraw(); } void DidFinishImplFrame() override {} @@ -128,13 +126,6 @@ return last_begin_main_frame_args_; } - void ScheduledActionAnimate() override { - PushAction("ScheduledActionAnimate"); - if (animate_causes_redraw_) - scheduler_->SetNeedsRedraw(); - if (animate_causes_animate_) - scheduler_->SetNeedsAnimate(); - } DrawResult ScheduledActionDrawAndSwapIfPossible() override { PushAction("ScheduledActionDrawAndSwapIfPossible"); num_draws_++; @@ -206,8 +197,7 @@ return scheduler_->BeginImplFrameDeadlinePending() == state; } - bool animate_causes_redraw_; - bool animate_causes_animate_; + bool will_begin_impl_frame_causes_redraw_; bool will_begin_impl_frame_requests_one_begin_impl_frame_; bool draw_will_happen_; bool swap_will_happen_if_draw_happens_; @@ -583,8 +573,7 @@ // BeginImplFrame should prepare the draw. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); @@ -654,8 +643,7 @@ client_->Reset(); AdvanceFrame(); // BeginMainFrame is not sent during the defer commit is on. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); client_->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. @@ -705,8 +693,7 @@ client_->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); // Because we just swapped, the Scheduler should also request the next @@ -733,8 +720,7 @@ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); @@ -1032,8 +1018,7 @@ // the deadline task. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); // On the deadline, he actions should have occured in the right order. @@ -1060,8 +1045,7 @@ // the deadline task. client->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); // Draw. The draw will trigger SetNeedsPrepareTiles, and @@ -1124,8 +1108,7 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1147,8 +1130,7 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -1170,8 +1152,7 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1195,8 +1176,7 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(scheduler_->PrepareTilesPending()); @@ -1214,8 +1194,7 @@ scheduler_->SetNeedsRedraw(); client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -1253,8 +1232,7 @@ client_->Reset(); AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -1508,10 +1486,9 @@ scheduler_->SetNeedsRedraw(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 4); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 4); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3); client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); @@ -1519,10 +1496,9 @@ scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); // Verify we skip every other frame if the swap ack consistently // comes back late. @@ -1558,19 +1534,17 @@ client_->Reset(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2); client_->Reset(); scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); } } @@ -1644,9 +1618,8 @@ scheduler_->SetNeedsRedraw(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 3); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2); client_->Reset(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); @@ -1678,8 +1651,7 @@ client_->Reset(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); client_->Reset(); // Deadline should be immediate. @@ -1709,10 +1681,9 @@ scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); // Verify impl thread consistently operates in high latency mode // without skipping any frames. @@ -1735,11 +1706,10 @@ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); // Verify that we don't skip the actions of the BeginImplFrame - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 0, 5); - EXPECT_ACTION("ScheduledActionCommit", client_, 1, 5); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 2, 5); - EXPECT_ACTION("ScheduledActionAnimate", client_, 3, 5); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 0, 4); + EXPECT_ACTION("ScheduledActionCommit", client_, 1, 4); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 2, 4); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); } } @@ -1837,12 +1807,11 @@ scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 6); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 6); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 6); - EXPECT_ACTION("ScheduledActionCommit", client_, 4, 6); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 5, 6); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 5); + EXPECT_ACTION("ScheduledActionCommit", client_, 3, 5); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 4, 5); // Don't call scheduler_->DidSwapBuffersComplete() until after next frame // to put the impl thread in a high latency mode. @@ -1853,8 +1822,7 @@ EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); // Note: BeginMainFrame and swap are skipped here because of // swap ack backpressure, not because of latency recovery. EXPECT_FALSE(client_->HasAction("ScheduledActionSendBeginMainFrame")); @@ -1879,9 +1847,8 @@ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); // Verify we skip the BeginImplFrame second. client_->Reset(); @@ -1911,12 +1878,11 @@ scheduler_->DidSwapBuffersComplete(); EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 6); - EXPECT_ACTION("ScheduledActionCommit", client_, 2, 6); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 3, 6); - EXPECT_ACTION("ScheduledActionAnimate", client_, 4, 6); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 5, 6); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5); + EXPECT_ACTION("ScheduledActionCommit", client_, 2, 5); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 3, 5); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5); } TEST_F( @@ -1948,13 +1914,12 @@ scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); EXPECT_FALSE(scheduler_->CommitPending()); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 7); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 7); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 7); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 7); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 7); - EXPECT_ACTION("ScheduledActionCommit", client_, 5, 7); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 6, 7); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 6); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 6); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 6); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 6); + EXPECT_ACTION("ScheduledActionCommit", client_, 4, 6); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 5, 6); // Make sure that we can finish the next commit even while swap throttled. client_->Reset(); @@ -1967,11 +1932,9 @@ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 5); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5); - EXPECT_ACTION("ScheduledActionCommit", client_, 3, 5); - EXPECT_ACTION("ScheduledActionAnimate", client_, 4, 5); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionCommit", client_, 2, 3); // Make sure we do not send a BeginMainFrame while swap throttled and // we have both a pending tree and an active tree. @@ -1981,8 +1944,7 @@ EXPECT_SCOPED(AdvanceFrame()); EXPECT_FALSE(scheduler_->CommitPending()); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); } TEST_F(SchedulerTest, @@ -2018,12 +1980,11 @@ scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); scheduler_->NotifyReadyToCommit(); EXPECT_FALSE(scheduler_->CommitPending()); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 6); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 6); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 6); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 6); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 6); - EXPECT_ACTION("ScheduledActionCommit", client_, 5, 6); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 5); + EXPECT_ACTION("ScheduledActionCommit", client_, 4, 5); // Start another commit while we still have aa pending tree. // Enter a swap throttled state. @@ -2037,10 +1998,9 @@ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); // Can't commit yet because there's still a pending tree. client_->Reset(); @@ -2062,8 +2022,7 @@ EXPECT_SCOPED(AdvanceFrame()); EXPECT_FALSE(scheduler_->CommitPending()); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); } TEST_F( @@ -2098,12 +2057,11 @@ scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); scheduler_->NotifyReadyToCommit(); EXPECT_FALSE(scheduler_->CommitPending()); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 6); - EXPECT_ACTION("WillBeginImplFrame", client_, 1, 6); - EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 6); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 6); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 6); - EXPECT_ACTION("ScheduledActionCommit", client_, 5, 6); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5); + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 5); + EXPECT_ACTION("ScheduledActionCommit", client_, 4, 5); // Start another commit while we still have an active tree. client_->Reset(); @@ -2117,10 +2075,9 @@ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); scheduler_->DidSwapBuffersComplete(); scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); // Can't commit yet because there's still a pending tree. client_->Reset(); @@ -2184,8 +2141,7 @@ // BeginImplFrame should prepare the draw. task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); @@ -2246,12 +2202,11 @@ // The deadline task should trigger causing a draw. EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); // Keep animating. client_->Reset(); - scheduler_->SetNeedsAnimate(); + scheduler_->SetNeedsOneBeginImplFrame(); scheduler_->SetNeedsRedraw(); EXPECT_NO_ACTION(client_); @@ -2260,8 +2215,7 @@ // The retro frame hasn't expired yet. task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false)); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); // This is an immediate deadline case. @@ -2307,12 +2261,11 @@ // The deadline task should trigger causing a draw. EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); // Keep animating. client_->Reset(); - scheduler_->SetNeedsAnimate(); + scheduler_->SetNeedsOneBeginImplFrame(); scheduler_->SetNeedsRedraw(); EXPECT_NO_ACTION(client_); @@ -2415,8 +2368,7 @@ // BeginImplFrame should prepare the draw. task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -2505,8 +2457,7 @@ // Swapping will put us into a swap throttled state. // Run posted deadline. task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -2515,8 +2466,7 @@ scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -2535,8 +2485,7 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -2716,8 +2665,7 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -2842,8 +2790,7 @@ // BeginImplFrame should prepare the draw. client_->Reset(); task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); @@ -2934,8 +2881,7 @@ client_->Reset(); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); // Idle time between BeginFrames. client_->Reset(); @@ -2986,8 +2932,7 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); @@ -3001,8 +2946,7 @@ // Unthrottled frame source will immediately begin a new frame. task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3025,8 +2969,7 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); // Switch to an unthrottled frame source before the frame deadline is hit. scheduler_->SetThrottleFrameProduction(false); @@ -3044,8 +2987,7 @@ client_->Reset(); task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); } @@ -3062,8 +3004,7 @@ client_->Reset(); task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3083,8 +3024,7 @@ client_->Reset(); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); @@ -3108,12 +3048,11 @@ scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); task_runner().RunPendingTasks(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 6); - EXPECT_ACTION("ScheduledActionCommit", client_, 2, 6); - EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 3, 6); - EXPECT_ACTION("ScheduledActionAnimate", client_, 4, 6); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 5, 6); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5); + EXPECT_ACTION("ScheduledActionCommit", client_, 2, 5); + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 3, 5); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5); client_->Reset(); // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) @@ -3134,39 +3073,37 @@ scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsAnimate(); + scheduler_->SetNeedsOneBeginImplFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); - // Testing the case where the animate ticks a fling scroll. - client_->SetAnimateCausesRedraw(true); + // Testing the case where animation ticks a fling scroll. + client_->SetWillBeginImplFrameCausesRedraw(true); // The animation isn't done so it'll cause another tick in the future. - client_->SetAnimateCausesAnimate(true); + client_->SetWillBeginImplFrameRequestsOneBeginImplFrame(true); // Next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); - // Android onDraw. This doesn't consume the animate tick. + // Android onDraw. This doesn't consume the single begin frame request. scheduler_->SetNeedsRedraw(); scheduler_->OnDrawForOutputSurface(); EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); - // The animate changes stuff on the screen, but ends here, so does not - // cause another animate step. - client_->SetAnimateCausesRedraw(true); + // The animation inside of WillBeginImplFrame changes stuff on the screen, but + // ends here, so does not cause another frame to happen. + client_->SetWillBeginImplFrameCausesRedraw(true); // Next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3177,7 +3114,7 @@ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); - // Idle on next vsync, as the animate has completed. + // Idle on next vsync, as the animation has completed. AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3); @@ -3193,9 +3130,8 @@ scheduler_->SetNeedsRedraw(); scheduler_->OnDrawForOutputSurface(); - EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3281,9 +3217,8 @@ // Next vsync. AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3334,10 +3269,9 @@ scheduler_->SetNeedsBeginMainFrame(); AdvanceFrame(); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 3, 4); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 3); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -3375,9 +3309,8 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); client_->Reset(); // Android onDraw. @@ -3420,9 +3353,8 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); client_->Reset(); // Android onDraw. @@ -3449,9 +3381,8 @@ // Next vsync. EXPECT_SCOPED(AdvanceFrame()); - EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); - EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); - EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3); + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); + EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 1, 2); client_->Reset(); // Android onDraw. @@ -3478,10 +3409,8 @@ scheduler_->SetNeedsRedraw(); scheduler_->OnDrawForOutputSurface(); - // Action animate is the result of SetNeedsRedraw. - EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); // SynchronousCompositor has to draw regardless of visibility. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); }
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h index 961f0f26..d8ae782 100644 --- a/cc/test/fake_layer_tree_host_impl_client.h +++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -27,7 +27,7 @@ void NotifyReadyToDraw() override {} void SetNeedsRedrawOnImplThread() override {} void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {} - void SetNeedsAnimateOnImplThread() override {} + void SetNeedsOneBeginImplFrameOnImplThread() override {} void SetNeedsCommitOnImplThread() override {} void SetNeedsPrepareTilesOnImplThread() override {} void SetVideoNeedsBeginFrames(bool needs_begin_frames) override {}
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc index 264b24b..1025192 100644 --- a/cc/test/fake_tile_manager.cc +++ b/cc/test/fake_tile_manager.cc
@@ -19,12 +19,10 @@ class FakeTileTaskRunnerImpl : public TileTaskRunner, public TileTaskClient { public: // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override {} void Shutdown() override {} - void ScheduleTasks(TileTaskQueue* queue) override { - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - RasterTask* task = it->task; + void ScheduleTasks(TaskGraph* graph) override { + for (const auto& node : graph->nodes) { + RasterTask* task = static_cast<RasterTask*>(node.task); task->WillSchedule(); task->ScheduleOnOriginThread(this);
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 655c5d4e..a8241ae 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -147,11 +147,6 @@ return result; } - void ScheduledActionAnimate() override { - ThreadProxy::ScheduledActionAnimate(); - test_hooks_->ScheduledActionAnimate(); - } - void ScheduledActionCommit() override { ThreadProxy::ScheduledActionCommit(); test_hooks_->ScheduledActionCommit(); @@ -345,7 +340,7 @@ test_hooks_(test_hooks) {} }; -// Adapts ThreadProxy for test. Injects test hooks for testing. +// Adapts SingleThreadProxy for test. Injects test hooks for testing. class SingleThreadProxyForTest : public SingleThreadProxy { public: static scoped_ptr<Proxy> Create( @@ -377,11 +372,6 @@ return result; } - void ScheduledActionAnimate() override { - SingleThreadProxy::ScheduledActionAnimate(); - test_hooks_->ScheduledActionAnimate(); - } - void ScheduledActionCommit() override { SingleThreadProxy::ScheduledActionCommit(); test_hooks_->ScheduledActionCommit();
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index 2c22332..59e668d 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h
@@ -116,7 +116,6 @@ virtual void ScheduledActionWillSendBeginMainFrame() {} virtual void ScheduledActionSendBeginMainFrame() {} virtual void ScheduledActionDrawAndSwapIfPossible() {} - virtual void ScheduledActionAnimate() {} virtual void ScheduledActionCommit() {} virtual void ScheduledActionBeginOutputSurfaceCreation() {} virtual void ScheduledActionPrepareTiles() {}
diff --git a/cc/test/test_gles2_interface.cc b/cc/test/test_gles2_interface.cc index 4ebdfd3..2781712 100644 --- a/cc/test/test_gles2_interface.cc +++ b/cc/test/test_gles2_interface.cc
@@ -379,7 +379,8 @@ void TestGLES2Interface::ResizeCHROMIUM(GLuint width, GLuint height, - float device_scale) { + float device_scale, + GLboolean has_alpha) { test_context_->reshapeWithScaleFactor(width, height, device_scale); }
diff --git a/cc/test/test_gles2_interface.h b/cc/test/test_gles2_interface.h index 20ab0079..0914810 100644 --- a/cc/test/test_gles2_interface.h +++ b/cc/test/test_gles2_interface.h
@@ -157,7 +157,10 @@ GLuint CreateAndConsumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override; - void ResizeCHROMIUM(GLuint width, GLuint height, float device_scale) override; + void ResizeCHROMIUM(GLuint width, + GLuint height, + float device_scale, + GLboolean has_alpha) override; void LoseContextCHROMIUM(GLenum current, GLenum other) override; GLenum GetGraphicsResetStatusKHR() override;
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h index 8fa4496..4e6d7611 100644 --- a/cc/test/test_web_graphics_context_3d.h +++ b/cc/test/test_web_graphics_context_3d.h
@@ -314,6 +314,9 @@ void set_have_post_sub_buffer(bool have) { test_capabilities_.gpu.post_sub_buffer = have; } + void set_have_commit_overlay_planes(bool have) { + test_capabilities_.gpu.commit_overlay_planes = have; + } void set_have_discard_framebuffer(bool have) { test_capabilities_.gpu.discard_framebuffer = have; }
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc index 477025f..9804da0 100644 --- a/cc/tiles/tile_manager.cc +++ b/cc/tiles/tile_manager.cc
@@ -153,20 +153,91 @@ DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl); }; -const char* TaskSetName(TaskSet task_set) { - switch (task_set) { - case TileManager::ALL: - return "ALL"; - case TileManager::REQUIRED_FOR_ACTIVATION: - return "REQUIRED_FOR_ACTIVATION"; - case TileManager::REQUIRED_FOR_DRAW: - return "REQUIRED_FOR_DRAW"; +// Task priorities that make sure that the task set done tasks run before any +// other remaining tasks. +const size_t kRequiredForActivationDoneTaskPriority = 1u; +const size_t kRequiredForDrawDoneTaskPriority = 2u; +const size_t kAllDoneTaskPriority = 3u; + +// For correctness, |kTileTaskPriorityBase| must be greater than +// all task set done task priorities. +size_t kTileTaskPriorityBase = 10u; + +void InsertNodeForTask(TaskGraph* graph, + TileTask* task, + size_t priority, + size_t dependencies) { + DCHECK(std::find_if(graph->nodes.begin(), graph->nodes.end(), + [task](const TaskGraph::Node& node) { + return node.task == task; + }) == graph->nodes.end()); + graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies)); +} + +void InsertNodesForRasterTask(TaskGraph* graph, + RasterTask* raster_task, + const ImageDecodeTask::Vector& decode_tasks, + size_t priority) { + size_t dependencies = 0u; + + // Insert image decode tasks. + for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin(); + it != decode_tasks.end(); ++it) { + ImageDecodeTask* decode_task = it->get(); + + // Skip if already decoded. + if (decode_task->HasCompleted()) + continue; + + dependencies++; + + // Add decode task if it doesn't already exists in graph. + TaskGraph::Node::Vector::iterator decode_it = + std::find_if(graph->nodes.begin(), graph->nodes.end(), + [decode_task](const TaskGraph::Node& node) { + return node.task == decode_task; + }); + if (decode_it == graph->nodes.end()) + InsertNodeForTask(graph, decode_task, priority, 0u); + + graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task)); } - NOTREACHED(); - return "Invalid TaskSet"; + InsertNodeForTask(graph, raster_task, priority, dependencies); } +class TaskSetFinishedTaskImpl : public TileTask { + public: + explicit TaskSetFinishedTaskImpl( + base::SequencedTaskRunner* task_runner, + const base::Closure& on_task_set_finished_callback) + : task_runner_(task_runner), + on_task_set_finished_callback_(on_task_set_finished_callback) {} + + // Overridden from Task: + void RunOnWorkerThread() override { + TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread"); + TaskSetFinished(); + } + + // Overridden from TileTask: + void ScheduleOnOriginThread(TileTaskClient* client) override {} + void CompleteOnOriginThread(TileTaskClient* client) override {} + + protected: + ~TaskSetFinishedTaskImpl() override {} + + void TaskSetFinished() { + task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_); + } + + private: + scoped_refptr<base::SequencedTaskRunner> task_runner_; + const base::Closure on_task_set_finished_callback_; + + DISALLOW_COPY_AND_ASSIGN(TaskSetFinishedTaskImpl); +}; + } // namespace RasterTaskCompletionStats::RasterTaskCompletionStats() @@ -216,7 +287,8 @@ base::Unretained(this))), has_scheduled_tile_tasks_(false), prepare_tiles_count_(0u), - next_tile_id_(0u) {} + next_tile_id_(0u), + task_set_finished_weak_ptr_factory_(this) {} TileManager::~TileManager() { FinishTasksAndCleanUp(); @@ -228,13 +300,14 @@ global_state_ = GlobalStateThatImpactsTilePriority(); - TileTaskQueue empty; - tile_task_runner_->ScheduleTasks(&empty); - orphan_raster_tasks_.clear(); - - // This should finish all pending tasks and release any uninitialized - // resources. + // This cancels tasks if possible, finishes pending tasks, and release any + // uninitialized resources. tile_task_runner_->Shutdown(); + + // Now that all tasks have been finished, we can clear any + // |orphan_tasks_|. + orphan_tasks_.clear(); + tile_task_runner_->CheckForCompletedTasks(); FreeResourcesForReleasedTiles(); @@ -244,6 +317,7 @@ resource_pool_ = nullptr; more_tiles_need_prepare_check_notifier_.Cancel(); signals_check_notifier_.Cancel(); + task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); } void TileManager::SetResources(ResourcePool* resource_pool, @@ -255,7 +329,6 @@ scheduled_raster_task_limit_ = scheduled_raster_task_limit; resource_pool_ = resource_pool; tile_task_runner_ = tile_task_runner; - tile_task_runner_->SetClient(this); } void TileManager::Release(Tile* tile) { @@ -285,44 +358,45 @@ released_tiles_.swap(tiles_to_retain); } -void TileManager::DidFinishRunningTileTasks(TaskSet task_set) { - TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set", - TaskSetName(task_set)); +void TileManager::DidFinishRunningTileTasksRequiredForActivation() { + TRACE_EVENT0("cc", + "TileManager::DidFinishRunningTileTasksRequiredForActivation"); + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", + ScheduledTasksStateAsValue()); + signals_.ready_to_activate = true; + signals_check_notifier_.Schedule(); +} + +void TileManager::DidFinishRunningTileTasksRequiredForDraw() { + TRACE_EVENT0("cc", "TileManager::DidFinishRunningTileTasksRequiredForDraw"); + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", + ScheduledTasksStateAsValue()); + signals_.ready_to_draw = true; + signals_check_notifier_.Schedule(); +} + +void TileManager::DidFinishRunningAllTileTasks() { + TRACE_EVENT0("cc", "TileManager::DidFinishRunningAllTileTasks"); + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); DCHECK(resource_pool_); DCHECK(tile_task_runner_); - switch (task_set) { - case ALL: { - has_scheduled_tile_tasks_ = false; + has_scheduled_tile_tasks_ = false; - bool memory_usage_above_limit = resource_pool_->memory_usage_bytes() > - global_state_.soft_memory_limit_in_bytes; + bool memory_usage_above_limit = resource_pool_->memory_usage_bytes() > + global_state_.soft_memory_limit_in_bytes; - if (all_tiles_that_need_to_be_rasterized_are_scheduled_ && - !memory_usage_above_limit) { - // TODO(ericrk): We should find a better way to safely handle re-entrant - // notifications than always having to schedule a new task. - // http://crbug.com/498439 - signals_.all_tile_tasks_completed = true; - signals_check_notifier_.Schedule(); - return; - } - - more_tiles_need_prepare_check_notifier_.Schedule(); - return; - } - case REQUIRED_FOR_ACTIVATION: - signals_.ready_to_activate = true; - signals_check_notifier_.Schedule(); - return; - - case REQUIRED_FOR_DRAW: - signals_.ready_to_draw = true; - signals_check_notifier_.Schedule(); - return; + if (all_tiles_that_need_to_be_rasterized_are_scheduled_ && + !memory_usage_above_limit) { + // TODO(ericrk): We should find a better way to safely handle re-entrant + // notifications than always having to schedule a new task. + // http://crbug.com/498439 + signals_.all_tile_tasks_completed = true; + signals_check_notifier_.Schedule(); + return; } - NOTREACHED(); + more_tiles_need_prepare_check_notifier_.Schedule(); } bool TileManager::PrepareTiles( @@ -605,20 +679,41 @@ void TileManager::ScheduleTasks( const PrioritizedTileVector& tiles_that_need_to_be_rasterized) { - TRACE_EVENT1("cc", - "TileManager::ScheduleTasks", - "count", + TRACE_EVENT1("cc", "TileManager::ScheduleTasks", "count", tiles_that_need_to_be_rasterized.size()); DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_); - raster_queue_.Reset(); + if (!has_scheduled_tile_tasks_) { + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); + } + + // Cancel existing OnTaskSetFinished callbacks. + task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); // Even when scheduling an empty set of tiles, the TTWP does some work, and // will always trigger a DidFinishRunningTileTasks notification. Because of // this we unconditionally set |has_scheduled_tile_tasks_| to true. has_scheduled_tile_tasks_ = true; + // Track the number of dependents for each *_done task. + size_t required_for_activate_count = 0; + size_t required_for_draw_count = 0; + size_t all_count = 0; + + size_t priority = kTileTaskPriorityBase; + + graph_.Reset(); + + scoped_refptr<TileTask> required_for_activation_done_task = + CreateTaskSetFinishedTask( + &TileManager::DidFinishRunningTileTasksRequiredForActivation); + scoped_refptr<TileTask> required_for_draw_done_task = + CreateTaskSetFinishedTask( + &TileManager::DidFinishRunningTileTasksRequiredForDraw); + scoped_refptr<TileTask> all_done_task = + CreateTaskSetFinishedTask(&TileManager::DidFinishRunningAllTileTasks); + // Build a new task queue containing all task currently needed. Tasks // are added in order of priority, highest priority task first. for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) { @@ -627,19 +722,40 @@ DCHECK(tile->draw_info().requires_resource()); DCHECK(!tile->draw_info().resource_); + if (!tile->raster_task_) { + tile->raster_task_ = CreateRasterTask(prioritized_tile); + } + + RasterTask* task = tile->raster_task_.get(); + DCHECK(!task->HasCompleted()); + if (!tile->raster_task_.get()) tile->raster_task_ = CreateRasterTask(prioritized_tile); - TaskSetCollection task_sets; - if (tile->required_for_activation()) - task_sets.set(REQUIRED_FOR_ACTIVATION); - if (tile->required_for_draw()) - task_sets.set(REQUIRED_FOR_DRAW); - task_sets.set(ALL); - raster_queue_.items.push_back( - TileTaskQueue::Item(tile->raster_task_.get(), task_sets)); + if (tile->required_for_activation()) { + required_for_activate_count++; + graph_.edges.push_back( + TaskGraph::Edge(task, required_for_activation_done_task.get())); + } + if (tile->required_for_draw()) { + required_for_draw_count++; + graph_.edges.push_back( + TaskGraph::Edge(task, required_for_draw_done_task.get())); + } + all_count++; + graph_.edges.push_back(TaskGraph::Edge(task, all_done_task.get())); + + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); } + InsertNodeForTask(&graph_, required_for_activation_done_task.get(), + kRequiredForActivationDoneTaskPriority, + required_for_activate_count); + InsertNodeForTask(&graph_, required_for_draw_done_task.get(), + kRequiredForDrawDoneTaskPriority, required_for_draw_count); + InsertNodeForTask(&graph_, all_done_task.get(), kAllDoneTaskPriority, + all_count); + // We must reduce the amount of unused resoruces before calling // ScheduleTasks to prevent usage from rising above limits. resource_pool_->ReduceResourceUsage(); @@ -647,14 +763,23 @@ // Schedule running of |raster_queue_|. This replaces any previously // scheduled tasks and effectively cancels all tasks not present // in |raster_queue_|. - tile_task_runner_->ScheduleTasks(&raster_queue_); + tile_task_runner_->ScheduleTasks(&graph_); // It's now safe to clean up orphan tasks as raster worker pool is not // allowed to keep around unreferenced raster tasks after ScheduleTasks() has // been called. - orphan_raster_tasks_.clear(); + orphan_tasks_.clear(); + + // It's also now safe to replace our *_done_task_ tasks. + required_for_activation_done_task_ = + std::move(required_for_activation_done_task); + required_for_draw_done_task_ = std::move(required_for_draw_done_task); + all_done_task_ = std::move(all_done_task); did_check_for_completed_tasks_since_last_schedule_tasks_ = false; + + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", + ScheduledTasksStateAsValue()); } scoped_refptr<RasterTask> TileManager::CreateRasterTask( @@ -709,7 +834,7 @@ Tile* tile = tiles_[tile_id]; DCHECK(tile->raster_task_.get()); - orphan_raster_tasks_.push_back(tile->raster_task_); + orphan_tasks_.push_back(tile->raster_task_); tile->raster_task_ = nullptr; if (was_canceled) { @@ -773,7 +898,6 @@ void TileManager::SetTileTaskRunnerForTesting( TileTaskRunner* tile_task_runner) { tile_task_runner_ = tile_task_runner; - tile_task_runner_->SetClient(this); } bool TileManager::AreRequiredTilesReadyToDraw( @@ -947,9 +1071,32 @@ return tile_task_runner_->GetResourceRequiresSwizzle(!tile->is_opaque()); } -TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) { +scoped_refptr<base::trace_event::ConvertableToTraceFormat> +TileManager::ScheduledTasksStateAsValue() const { + scoped_refptr<base::trace_event::TracedValue> state = + new base::trace_event::TracedValue(); + + state->BeginDictionary("tasks_pending"); + state->SetBoolean("ready_to_activate", signals_.ready_to_activate); + state->SetBoolean("ready_to_draw", signals_.ready_to_draw); + state->SetBoolean("all_tile_tasks_completed", + signals_.all_tile_tasks_completed); + state->EndDictionary(); + return state; } +// Utility function that can be used to create a "Task set finished" task that +// posts |callback| to |task_runner| when run. +scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask( + void (TileManager::*callback)()) { + return make_scoped_refptr(new TaskSetFinishedTaskImpl( + task_runner_.get(), + base::Bind(callback, task_set_finished_weak_ptr_factory_.GetWeakPtr()))); +} + +TileManager::MemoryUsage::MemoryUsage() + : memory_bytes_(0), resource_count_(0) {} + TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes, size_t resource_count) : memory_bytes_(static_cast<int64>(memory_bytes)),
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h index abffc7c..c041ce24 100644 --- a/cc/tiles/tile_manager.h +++ b/cc/tiles/tile_manager.h
@@ -5,8 +5,6 @@ #ifndef CC_TILES_TILE_MANAGER_H_ #define CC_TILES_TILE_MANAGER_H_ -#include <deque> -#include <queue> #include <set> #include <utility> #include <vector> @@ -90,26 +88,13 @@ // should no longer have any memory assigned to them. Tile objects are "owned" // by layers; they automatically register with the manager when they are // created, and unregister from the manager when they are deleted. -class CC_EXPORT TileManager : public TileTaskRunnerClient { +class CC_EXPORT TileManager { public: - enum NamedTaskSet { - REQUIRED_FOR_ACTIVATION, - REQUIRED_FOR_DRAW, - // PixelBufferTileTaskWorkerPool depends on ALL being last. - ALL - // Adding additional values requires increasing kNumberOfTaskSets in - // tile_task_runner.h - }; - - static_assert(NamedTaskSet::ALL == (kNumberOfTaskSets - 1), - "NamedTaskSet::ALL should be equal to kNumberOfTaskSets" - "minus 1"); - static scoped_ptr<TileManager> Create(TileManagerClient* client, base::SequencedTaskRunner* task_runner, size_t scheduled_raster_task_limit, bool use_partial_raster); - ~TileManager() override; + virtual ~TileManager(); // Assigns tile memory and schedules work to prepare tiles for drawing. // - Runs client_->NotifyReadyToActivate() when all tiles required for @@ -217,9 +202,6 @@ virtual void Release(Tile* tile); Tile::Id GetUniqueTileId() { return ++next_tile_id_; } - // Overriden from TileTaskRunnerClient: - void DidFinishRunningTileTasks(TaskSet task_set) override; - typedef std::vector<PrioritizedTile> PrioritizedTileVector; typedef std::set<Tile*> TileSet; @@ -288,6 +270,16 @@ ResourceFormat DetermineResourceFormat(const Tile* tile) const; bool DetermineResourceRequiresSwizzle(const Tile* tile) const; + void DidFinishRunningTileTasksRequiredForActivation(); + void DidFinishRunningTileTasksRequiredForDraw(); + void DidFinishRunningAllTileTasks(); + + scoped_refptr<TileTask> CreateTaskSetFinishedTask( + void (TileManager::*callback)()); + + scoped_refptr<base::trace_event::ConvertableToTraceFormat> + ScheduledTasksStateAsValue() const; + TileManagerClient* client_; scoped_refptr<base::SequencedTaskRunner> task_runner_; ResourcePool* resource_pool_; @@ -311,10 +303,12 @@ std::vector<Tile*> released_tiles_; - // Queue used when scheduling raster tasks. - TileTaskQueue raster_queue_; + std::vector<scoped_refptr<TileTask>> orphan_tasks_; - std::vector<scoped_refptr<RasterTask>> orphan_raster_tasks_; + TaskGraph graph_; + scoped_refptr<TileTask> required_for_activation_done_task_; + scoped_refptr<TileTask> required_for_draw_done_task_; + scoped_refptr<TileTask> all_done_task_; UniqueNotifier more_tiles_need_prepare_check_notifier_; @@ -338,6 +332,8 @@ uint64_t prepare_tiles_count_; uint64_t next_tile_id_; + base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(TileManager); };
diff --git a/cc/tiles/tile_manager_perftest.cc b/cc/tiles/tile_manager_perftest.cc index 81213d45..e28f35a 100644 --- a/cc/tiles/tile_manager_perftest.cc +++ b/cc/tiles/tile_manager_perftest.cc
@@ -37,12 +37,10 @@ class FakeTileTaskRunnerImpl : public TileTaskRunner, public TileTaskClient { public: // Overridden from TileTaskRunner: - void SetClient(TileTaskRunnerClient* client) override {} void Shutdown() override {} - void ScheduleTasks(TileTaskQueue* queue) override { - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); - it != queue->items.end(); ++it) { - RasterTask* task = it->task; + void ScheduleTasks(TaskGraph* graph) override { + for (auto& node : graph->nodes) { + RasterTask* task = static_cast<RasterTask*>(node.task); task->WillSchedule(); task->ScheduleOnOriginThread(this);
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index f6ec9c0..795118f 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -1698,7 +1698,6 @@ ~FakeTileTaskRunner() override {} // TileTaskRunner methods. - void SetClient(TileTaskRunnerClient* client) override {} void Shutdown() override {} void CheckForCompletedTasks() override {} ResourceFormat GetResourceFormat(bool must_support_alpha) const override { @@ -1708,7 +1707,7 @@ return false; } - void ScheduleTasks(TileTaskQueue* queue) override {} + void ScheduleTasks(TaskGraph* graph) override {} // TileTaskClient methods. scoped_ptr<RasterBuffer> AcquireBufferForRaster( @@ -1727,11 +1726,11 @@ CancellingTileTaskRunner() {} ~CancellingTileTaskRunner() override {} - void ScheduleTasks(TileTaskQueue* queue) override { + void ScheduleTasks(TaskGraph* graph) override { // Just call CompleteOnOriginThread on each item in the queue. As none of // these items have run yet, they will be treated as cancelled tasks. - for (const auto& task : queue->items) { - task.task->CompleteOnOriginThread(this); + for (const auto& node : graph->nodes) { + static_cast<RasterTask*>(node.task)->CompleteOnOriginThread(this); } } }; @@ -1804,12 +1803,13 @@ : expected_resource_id_(expected_resource_id) {} ~VerifyResourceContentIdTileTaskRunner() override {} - void ScheduleTasks(TileTaskQueue* queue) override { - for (const auto& task : queue->items) { + void ScheduleTasks(TaskGraph* graph) override { + for (const auto& node : graph->nodes) { + RasterTask* task = static_cast<RasterTask*>(node.task); // Triggers a call to AcquireBufferForRaster. - task.task->ScheduleOnOriginThread(this); + task->ScheduleOnOriginThread(this); // Calls TileManager as though task was cancelled. - task.task->CompleteOnOriginThread(this); + task->CompleteOnOriginThread(this); } }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 0ce5d0e0..fdf32f0 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -335,7 +335,10 @@ // change the results. When doing commit to the active tree, this must happen // after ActivateAnimations() in order for this ticking to be propogated to // layers on the active tree. - AnimatePendingTreeAfterCommit(); + if (CommitToActiveTree()) + Animate(); + else + AnimatePendingTreeAfterCommit(); // LayerTreeHost may have changed the GPU rasterization flags state, which // may require an update of the tree resources. @@ -508,7 +511,7 @@ duration.InSecondsF()); } - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); client_->SetNeedsCommitOnImplThread(); client_->RenewTreePriority(); } @@ -516,7 +519,7 @@ void LayerTreeHostImpl::SetNeedsAnimateInput() { DCHECK(!IsCurrentlyScrollingInnerViewport() || !settings_.ignore_root_layer_flings); - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); } bool LayerTreeHostImpl::IsCurrentlyScrollingInnerViewport() const { @@ -1848,6 +1851,8 @@ SetNeedsRedraw(); } + Animate(); + for (auto& it : video_frame_controllers_) it->OnBeginFrame(args); } @@ -2061,9 +2066,12 @@ renderer_->SetVisible(visible); } -void LayerTreeHostImpl::SetNeedsAnimate() { +void LayerTreeHostImpl::SetNeedsOneBeginImplFrame() { + // TODO(miletus): This is just the compositor-thread-side call to the + // SwapPromiseMonitor to say something happened that may cause a swap in the + // future. The name should not refer to SetNeedsRedraw but it does for now. NotifySwapPromiseMonitorsOfSetNeedsRedraw(); - client_->SetNeedsAnimateOnImplThread(); + client_->SetNeedsOneBeginImplFrameOnImplThread(); } void LayerTreeHostImpl::SetNeedsRedraw() { @@ -2387,7 +2395,7 @@ void LayerTreeHostImpl::DidChangeTopControlsPosition() { UpdateViewportContainerSizes(); SetNeedsRedraw(); - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); active_tree_->set_needs_update_draw_properties(); SetFullRootLayerDamage(); } @@ -2592,7 +2600,7 @@ ScrollAnimationCreate(layer_impl, target_offset, current_offset); - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); return SCROLL_STARTED; } } @@ -3105,7 +3113,7 @@ client_->RenewTreePriority(); client_->DidCompletePageScaleAnimationOnImplThread(); } else { - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); } return true; } @@ -3117,7 +3125,7 @@ gfx::Vector2dF scroll = top_controls_manager_->Animate(time); if (top_controls_manager_->animation()) - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); if (active_tree_->TotalScrollOffset().y() == 0.f) return false; @@ -3133,9 +3141,10 @@ } bool LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks monotonic_time) { - for (auto& it : scrollbar_animation_controllers_) - it.second->Animate(monotonic_time); - return !scrollbar_animation_controllers_.empty(); + bool animated = false; + for (auto& pair : scrollbar_animation_controllers_) + animated |= pair.second->Animate(monotonic_time); + return animated; } bool LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) { @@ -3151,16 +3160,17 @@ animated = true; } - // TODO(ajuma): Only do this if the animations are on the active tree, or if - // they are on the pending tree waiting for some future time to start. - // TODO(ajuma): We currently have a single signal from the animation - // host/registrar, so on the last frame of an animation we will still request - // an extra SetNeedsAnimate here. + // TODO(crbug.com/551134): Only do this if the animations are on the active + // tree, or if they are on the pending tree waiting for some future time to + // start. + // TODO(crbug.com/551138): We currently have a single signal from the + // animation host/registrar, so on the last frame of an animation we will + // still request an extra SetNeedsAnimate here. if (animated) - SetNeedsAnimate(); - // TODO(danakj): We could return true only if the animations are on the active - // tree. There's no need to cause a draw to take place from animations - // starting/ticking on the pending tree. + SetNeedsOneBeginImplFrame(); + // TODO(crbug.com/551138): We could return true only if the animations are on + // the active tree. There's no need to cause a draw to take place from + // animations starting/ticking on the pending tree. return animated; } @@ -3185,7 +3195,7 @@ client_->PostAnimationEventsToMainThreadOnImplThread(std::move(events)); if (has_active_animations) - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); } void LayerTreeHostImpl::ActivateAnimations() { @@ -3202,12 +3212,12 @@ } if (activated) { - SetNeedsAnimate(); // Activating an animation changes layer draw properties, such as - // screen_space_transform_is_animating, or changes transforms etc. So when - // we see a new animation get activated, we need to update the draw - // properties on the active tree. + // screen_space_transform_is_animating. So when we see a new animation get + // activated, we need to update the draw properties on the active tree. active_tree()->set_needs_update_draw_properties(); + // Request another frame to run the next tick of the animation. + SetNeedsOneBeginImplFrame(); } } @@ -3255,11 +3265,15 @@ client_->PostDelayedAnimationTaskOnImplThread(task, delay); } +// TODO(danakj): Make this a return value from the Animate() call instead of an +// interface on LTHI. (Also, crbug.com/551138.) void LayerTreeHostImpl::SetNeedsAnimateForScrollbarAnimation() { TRACE_EVENT0("cc", "LayerTreeHostImpl::SetNeedsAnimateForScrollbarAnimation"); - SetNeedsAnimate(); + SetNeedsOneBeginImplFrame(); } +// TODO(danakj): Make this a return value from the Animate() call instead of an +// interface on LTHI. (Also, crbug.com/551138.) void LayerTreeHostImpl::SetNeedsRedrawForScrollbarAnimation() { SetNeedsRedraw(); }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 4f19f634..119e57e 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -103,10 +103,10 @@ virtual void NotifyReadyToDraw() = 0; // Please call these 3 functions through // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and - // SetNeedsAnimate(). + // SetNeedsOneBeginImplFrame(). virtual void SetNeedsRedrawOnImplThread() = 0; virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) = 0; - virtual void SetNeedsAnimateOnImplThread() = 0; + virtual void SetNeedsOneBeginImplFrameOnImplThread() = 0; virtual void SetNeedsCommitOnImplThread() = 0; virtual void SetNeedsPrepareTilesOnImplThread() = 0; virtual void SetVideoNeedsBeginFrames(bool needs_begin_frames) = 0; @@ -445,7 +445,7 @@ bool visible() const { return visible_; } void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); } - void SetNeedsAnimate(); + void SetNeedsOneBeginImplFrame(); void SetNeedsRedraw(); ManagedMemoryPolicy ActualManagedMemoryPolicy() const;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 6ee81330..0f58bfa0 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -88,7 +88,7 @@ did_notify_ready_to_activate_(false), did_request_commit_(false), did_request_redraw_(false), - did_request_animate_(false), + did_request_next_frame_(false), did_request_prepare_tiles_(false), did_complete_page_scale_animation_(false), reduce_memory_result_(true) { @@ -130,7 +130,9 @@ void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override { did_request_redraw_ = true; } - void SetNeedsAnimateOnImplThread() override { did_request_animate_ = true; } + void SetNeedsOneBeginImplFrameOnImplThread() override { + did_request_next_frame_ = true; + } void SetNeedsPrepareTilesOnImplThread() override { did_request_prepare_tiles_ = true; } @@ -163,8 +165,16 @@ virtual bool CreateHostImpl(const LayerTreeSettings& settings, scoped_ptr<OutputSurface> output_surface) { + return CreateHostImplWithTaskRunnerProvider( + settings, std::move(output_surface), &task_runner_provider_); + } + + virtual bool CreateHostImplWithTaskRunnerProvider( + const LayerTreeSettings& settings, + scoped_ptr<OutputSurface> output_surface, + TaskRunnerProvider* task_runner_provider) { host_impl_ = LayerTreeHostImpl::Create( - settings, this, &task_runner_provider_, &stats_instrumentation_, + settings, this, task_runner_provider, &stats_instrumentation_, &shared_bitmap_manager_, &gpu_memory_buffer_manager_, &task_graph_runner_, 0); output_surface_ = std::move(output_surface); @@ -440,7 +450,7 @@ bool did_notify_ready_to_activate_; bool did_request_commit_; bool did_request_redraw_; - bool did_request_animate_; + bool did_request_next_frame_; bool did_request_prepare_tiles_; bool did_complete_page_scale_animation_; bool reduce_memory_result_; @@ -1090,6 +1100,8 @@ } TEST_F(LayerTreeHostImplTest, AnimationSchedulingPendingTree) { + EXPECT_FALSE(host_impl_->CommitToActiveTree()); + host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->CreatePendingTree(); @@ -1106,7 +1118,7 @@ child->SetDrawsContent(true); AddAnimatedTransformToLayer(child, 10.0, 3, 0); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); @@ -1118,12 +1130,12 @@ // be continuously ticked on the pending tree, so it should not request // another animation frame here. But we currently do so blindly if any // animation exists. - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); // The pending tree with an animation does not need to draw after animating. EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_redraw_ = false; did_request_commit_ = false; @@ -1131,7 +1143,7 @@ // When the animation activates, we should request another animation frame // to keep the animation moving. - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); // On activation we don't need to request a redraw for the animation, // activating will draw on its own when it's ready. EXPECT_FALSE(did_request_redraw_); @@ -1139,6 +1151,8 @@ } TEST_F(LayerTreeHostImplTest, AnimationSchedulingActiveTree) { + EXPECT_FALSE(host_impl_->CommitToActiveTree()); + host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetRootLayer( @@ -1164,25 +1178,82 @@ host_impl_->WillBeginImplFrame( CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now)); - EXPECT_FALSE(did_request_animate_); - EXPECT_FALSE(did_request_redraw_); + // TODO(crbug.com/551134): We always request a new frame and a draw for + // animations that are on the pending tree, but we don't need to do that + // unless they are waiting for some future time to start. + EXPECT_TRUE(did_request_next_frame_); + EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); - - host_impl_->ActivateAnimations(); - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_redraw_ = false; did_request_commit_ = false; + host_impl_->ActivateAnimations(); + + // On activating an animation, we should request another frame so that we'll + // continue ticking the animation. + EXPECT_TRUE(did_request_next_frame_); + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + did_request_next_frame_ = false; + did_request_redraw_ = false; + did_request_commit_ = false; + + // The next frame after activating, we'll tick the animation again. host_impl_->Animate(); // An animation exists on the active layer. Doing Animate() requests another // frame after the current one. - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); // The animation should cause us to draw at the frame's deadline. EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); } +TEST_F(LayerTreeHostImplTest, AnimationSchedulingCommitToActiveTree) { + FakeImplTaskRunnerProvider provider(nullptr); + CreateHostImplWithTaskRunnerProvider(DefaultSettings(), CreateOutputSurface(), + &provider); + EXPECT_TRUE(host_impl_->CommitToActiveTree()); + + host_impl_->SetViewportSize(gfx::Size(50, 50)); + + host_impl_->active_tree()->SetRootLayer( + LayerImpl::Create(host_impl_->active_tree(), 1)); + LayerImpl* root = host_impl_->active_tree()->root_layer(); + root->SetBounds(gfx::Size(50, 50)); + root->SetHasRenderSurface(true); + + root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 2)); + LayerImpl* child = root->children()[0].get(); + child->SetBounds(gfx::Size(10, 10)); + child->draw_properties().visible_layer_rect = gfx::Rect(10, 10); + child->SetDrawsContent(true); + AddAnimatedTransformToLayer(child, 10.0, 3, 0); + + // Set up the property trees so that UpdateDrawProperties will work in + // CommitComplete below. + LayerImplList list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, gfx::Size(50, 50), &list, 0); + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_FALSE(did_request_next_frame_); + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + + host_impl_->CommitComplete(); + + // Animations on the active tree should be started and ticked, and a new frame + // should be requested to continue ticking them. + EXPECT_TRUE(did_request_next_frame_); + EXPECT_TRUE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + + // Delete the LayerTreeHostImpl before the TaskRunnerProvider goes away. + host_impl_ = nullptr; +} + class MissingTilesLayer : public LayerImpl { public: MissingTilesLayer(LayerTreeImpl* layer_tree_impl, int id) @@ -1201,7 +1272,7 @@ bool has_missing_tiles_; }; -TEST_F(LayerTreeHostImplTest, AnimationSchedulingMarksLayerNotReady) { +TEST_F(LayerTreeHostImplTest, AnimationMarksLayerNotReady) { host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetRootLayer( @@ -1310,7 +1381,7 @@ host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); host_impl_->ScrollEnd(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); EXPECT_EQ(gfx::Size(50, 50), container_layer->bounds()); @@ -1789,7 +1860,7 @@ host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); host_impl_->ScrollEnd(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); @@ -1938,7 +2009,7 @@ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50)); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; host_impl_->active_tree()->SetPendingPageScaleAnimation( scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( gfx::Vector2d(), @@ -1947,34 +2018,34 @@ duration))); host_impl_->ActivateSyncTree(); EXPECT_FALSE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = start_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = halfway_through_animation; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; begin_frame_args.frame_time = end_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_commit_); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = @@ -1995,7 +2066,7 @@ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50)); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; host_impl_->active_tree()->SetPendingPageScaleAnimation( scoped_ptr<PendingPageScaleAnimation> (new PendingPageScaleAnimation( gfx::Vector2d(25, 25), @@ -2004,25 +2075,25 @@ duration))); host_impl_->ActivateSyncTree(); EXPECT_FALSE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = start_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_commit_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = end_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_commit_); host_impl_->DidFinishImplFrame(); @@ -2139,7 +2210,7 @@ // Recreate the PSA. Nothing should happen here since the tree containing the // PSA hasn't been activated yet. did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; host_impl_->sync_tree()->SetPendingPageScaleAnimation( scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( gfx::Vector2d(), @@ -2149,7 +2220,7 @@ begin_frame_args.frame_time = halfway_through_animation; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); host_impl_->DidFinishImplFrame(); @@ -2159,7 +2230,7 @@ EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePendingPageScaleAnimation().get()); EXPECT_FALSE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); start_time += base::TimeDelta::FromSeconds(10); third_through_animation += base::TimeDelta::FromSeconds(10); @@ -2168,43 +2239,43 @@ // From here on, make sure the animation runs as normal. did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = start_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = third_through_animation; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); // Another activation shouldn't have any effect on the animation. host_impl_->ActivateSyncTree(); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; begin_frame_args.frame_time = halfway_through_animation; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; begin_frame_args.frame_time = end_time; host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); EXPECT_TRUE(did_request_commit_); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = @@ -2333,7 +2404,7 @@ base::TimeTicks fake_now = base::TimeTicks::Now(); // A task will be posted to fade the initial scrollbar. - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_FALSE(animation_task_.Equals(base::Closure())); requested_animation_delay_ = base::TimeDelta(); @@ -2342,43 +2413,68 @@ // If no scroll happened during a scroll gesture, it should have no effect. host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL); host_impl_->ScrollEnd(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); + // Before the scrollbar animation exists, we should not get redraws. + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, fake_now); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); + EXPECT_FALSE(did_request_next_frame_); + did_request_next_frame_ = false; + EXPECT_FALSE(did_request_redraw_); + did_request_redraw_ = false; + EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); + EXPECT_TRUE(animation_task_.Equals(base::Closure())); + host_impl_->DidFinishImplFrame(); + // After a scroll, a scrollbar animation should be scheduled about 20ms from // now. host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL); host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5)); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); did_request_redraw_ = false; EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); host_impl_->ScrollEnd(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), requested_animation_delay_); EXPECT_FALSE(animation_task_.Equals(base::Closure())); + // Before the scrollbar animation begins, we should not get redraws. + begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, fake_now); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); + EXPECT_FALSE(did_request_next_frame_); + did_request_next_frame_ = false; + EXPECT_FALSE(did_request_redraw_); + did_request_redraw_ = false; + host_impl_->DidFinishImplFrame(); + + // Start the scrollbar animation. fake_now += requested_animation_delay_; requested_animation_delay_ = base::TimeDelta(); animation_task_.Run(); animation_task_ = base::Closure(); - EXPECT_TRUE(did_request_animate_); - did_request_animate_ = false; + EXPECT_TRUE(did_request_next_frame_); + did_request_next_frame_ = false; EXPECT_FALSE(did_request_redraw_); // After the scrollbar animation begins, we should start getting redraws. - BeginFrameArgs begin_frame_args = + begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, fake_now); host_impl_->WillBeginImplFrame(begin_frame_args); host_impl_->Animate(); - EXPECT_TRUE(did_request_animate_); - did_request_animate_ = false; + EXPECT_TRUE(did_request_next_frame_); + did_request_next_frame_ = false; EXPECT_TRUE(did_request_redraw_); did_request_redraw_ = false; EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); @@ -2389,7 +2485,7 @@ // scrollbar to appear and to schedule a scrollbar animation. host_impl_->InnerViewportScrollLayer()->PushScrollOffsetFromMainThread( gfx::ScrollOffset(5, 5)); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), requested_animation_delay_); @@ -2397,17 +2493,29 @@ requested_animation_delay_ = base::TimeDelta(); animation_task_ = base::Closure(); + // Scrolling should have stopped the animation, so we should not be getting + // redraws. + begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, fake_now); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); + EXPECT_FALSE(did_request_next_frame_); + did_request_next_frame_ = false; + EXPECT_FALSE(did_request_redraw_); + did_request_redraw_ = false; + host_impl_->DidFinishImplFrame(); + // Scrollbar animation is not triggered unnecessarily. host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL); host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0)); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); did_request_redraw_ = false; EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); host_impl_->ScrollEnd(); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); @@ -2415,7 +2523,7 @@ // Changing page scale triggers scrollbar animation. host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); host_impl_->active_tree()->SetPageScaleOnActiveTree(1.1f); - EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), requested_animation_delay_); @@ -7618,7 +7726,7 @@ SetupScrollAndContentsLayers(gfx::Size(100, 100)) ->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 10)); host_impl_->DidChangeTopControlsPosition(); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); } @@ -7743,13 +7851,13 @@ scroll_layer->CurrentScrollOffset().ToString()); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; // End the scroll while the controls are still offset from their limit. host_impl_->ScrollEnd(); ASSERT_TRUE(host_impl_->top_controls_manager()->animation()); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); @@ -7757,9 +7865,9 @@ // offset being at the origin. BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); - while (did_request_animate_) { + while (did_request_next_frame_) { did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; float old_offset = @@ -7783,7 +7891,7 @@ if (new_offset != 0) { EXPECT_TRUE(host_impl_->top_controls_manager()->animation()); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); } host_impl_->DidFinishImplFrame(); } @@ -7817,22 +7925,22 @@ scroll_layer->CurrentScrollOffset().ToString()); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; // End the scroll while the controls are still offset from the limit. host_impl_->ScrollEnd(); ASSERT_TRUE(host_impl_->top_controls_manager()->animation()); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); // Animate the top controls to the limit. BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); - while (did_request_animate_) { + while (did_request_next_frame_) { did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; float old_offset = @@ -7884,22 +7992,22 @@ scroll_layer->CurrentScrollOffset().ToString()); did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; // End the fling while the controls are still offset from the limit. host_impl_->MainThreadHasStoppedFlinging(); ASSERT_TRUE(host_impl_->top_controls_manager()->animation()); - EXPECT_TRUE(did_request_animate_); + EXPECT_TRUE(did_request_next_frame_); EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_commit_); // Animate the top controls to the limit. BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); - while (did_request_animate_) { + while (did_request_next_frame_) { did_request_redraw_ = false; - did_request_animate_ = false; + did_request_next_frame_ = false; did_request_commit_ = false; float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset();
diff --git a/cc/trees/layer_tree_host_unittest_animation_timelines.cc b/cc/trees/layer_tree_host_unittest_animation_timelines.cc index acb8197..1c62e37 100644 --- a/cc/trees/layer_tree_host_unittest_animation_timelines.cc +++ b/cc/trees/layer_tree_host_unittest_animation_timelines.cc
@@ -217,6 +217,10 @@ void AnimateLayers(LayerTreeHostImpl* host_impl, base::TimeTicks monotonic_time) override { + // Wait for the commit with the animation to happen. + if (host_impl->sync_tree()->source_frame_number() != 0) + return; + scoped_refptr<AnimationTimeline> timeline_impl = host_impl->animation_host()->GetTimelineById(timeline_id_); scoped_refptr<AnimationPlayer> player_child_impl = @@ -224,12 +228,7 @@ LayerAnimationController* controller_impl = player_child_impl->element_animations()->layer_animation_controller(); - if (!controller_impl) - return; - Animation* animation = controller_impl->GetAnimation(Animation::OPACITY); - if (!animation) - return; const FloatAnimationCurve* curve = animation->curve()->ToFloatAnimationCurve();
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 46f26ff9..c8e5829 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -387,10 +387,12 @@ scheduler_on_impl_thread_->SetNeedsRedraw(); } -void SingleThreadProxy::SetNeedsAnimateOnImplThread() { +void SingleThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() { + TRACE_EVENT0("cc", + "SingleThreadProxy::SetNeedsOneBeginImplFrameOnImplThread"); client_->ScheduleComposite(); if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->SetNeedsAnimate(); + scheduler_on_impl_thread_->SetNeedsOneBeginImplFrame(); } void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() { @@ -713,6 +715,7 @@ } void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { + DebugScopedSetImplThread impl(task_runner_provider_); #if DCHECK_IS_ON() DCHECK(!inside_impl_frame_) << "WillBeginImplFrame called while already inside an impl frame!"; @@ -834,12 +837,6 @@ DoCommit(); } -void SingleThreadProxy::ScheduledActionAnimate() { - TRACE_EVENT0("cc", "ScheduledActionAnimate"); - DebugScopedSetImplThread impl(task_runner_provider_); - layer_tree_host_impl_->Animate(); -} - void SingleThreadProxy::ScheduledActionActivateSyncTree() { DebugScopedSetImplThread impl(task_runner_provider_); layer_tree_host_impl_->ActivateSyncTree();
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index edc522f3..a60f7139 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -71,7 +71,6 @@ DrawResult ScheduledActionDrawAndSwapIfPossible() override; DrawResult ScheduledActionDrawAndSwapForced() override; void ScheduledActionCommit() override; - void ScheduledActionAnimate() override; void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginOutputSurfaceCreation() override; void ScheduledActionPrepareTiles() override; @@ -93,7 +92,7 @@ void NotifyReadyToDraw() override; void SetNeedsRedrawOnImplThread() override; void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override; - void SetNeedsAnimateOnImplThread() override; + void SetNeedsOneBeginImplFrameOnImplThread() override; void SetNeedsPrepareTilesOnImplThread() override; void SetNeedsCommitOnImplThread() override; void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index 6ce4d47..7e09d7a 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc
@@ -436,10 +436,10 @@ impl().scheduler->SetNeedsRedraw(); } -void ThreadProxy::SetNeedsAnimateOnImplThread() { - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimateOnImplThread"); +void ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() { + TRACE_EVENT0("cc", "ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread"); DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetNeedsAnimate(); + impl().scheduler->SetNeedsOneBeginImplFrame(); } void ThreadProxy::SetNeedsPrepareTilesOnImplThread() { @@ -766,13 +766,6 @@ impl().scheduler->BeginMainFrameAborted(reason); } -void ThreadProxy::ScheduledActionAnimate() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate"); - DCHECK(task_runner_provider_->IsImplThread()); - - impl().layer_tree_host_impl->Animate(); -} - void ThreadProxy::ScheduledActionCommit() { TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit"); DCHECK(task_runner_provider_->IsImplThread());
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h index 771ada24..e10c57e6 100644 --- a/cc/trees/thread_proxy.h +++ b/cc/trees/thread_proxy.h
@@ -195,10 +195,10 @@ void NotifyReadyToDraw() override; // Please call these 3 functions through // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and - // SetNeedsAnimate(). + // SetNeedsOneBeginImplFrame(). void SetNeedsRedrawOnImplThread() override; void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override; - void SetNeedsAnimateOnImplThread() override; + void SetNeedsOneBeginImplFrameOnImplThread() override; void SetNeedsPrepareTilesOnImplThread() override; void SetNeedsCommitOnImplThread() override; void SetVideoNeedsBeginFrames(bool needs_begin_frames) override; @@ -225,7 +225,6 @@ void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override; DrawResult ScheduledActionDrawAndSwapIfPossible() override; DrawResult ScheduledActionDrawAndSwapForced() override; - void ScheduledActionAnimate() override; void ScheduledActionCommit() override; void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginOutputSurfaceCreation() override;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index b31d80f..b2ecaf4 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -434,7 +434,7 @@ # full symbols, but does work in other cases, including minimal # symbols. configs -= [ "//build/config/win:default_incremental_linking" ] - configs += [ "//build/config/win:incremental_linking" ] + configs += [ "//build/config/win:no_incremental_linking" ] } # TODO(GYP) bug 512851: PGO on Windows. # ['chrome_pgo_phase==1', {
diff --git a/chrome/VERSION b/chrome/VERSION index 3054a31..b2e8716 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=49 MINOR=0 -BUILD=2580 +BUILD=2581 PATCH=0
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml index 7936463..abd10677 100644 --- a/chrome/android/java/res/values/values.xml +++ b/chrome/android/java/res/values/values.xml
@@ -36,4 +36,23 @@ <string name="infobar_message_typeface">sans-serif</string> <integer name="infobar_message_textstyle">1</integer> + <!-- Help and Feedback + These constants should be in sync with the context names on go/mobilehelprecs. + If the context ID cannot be found, the default help page will be shown to the user.--> + <string name="help_context_new_tab">mobile_new_tab</string> + <string name="help_context_search_results">mobile_search_results</string> + <string name="help_context_webpage">mobile_webpage</string> + <string name="help_context_settings">mobile_settings</string> + <string name="help_context_incognito">mobile_incognito</string> + <string name="help_context_bookmarks">mobile_bookmarks</string> + <string name="help_context_history">mobile_history</string> + <string name="help_context_privacy">mobile_privacy</string> + <string name="help_context_translate">mobile_translate</string> + <string name="help_context_general">mobile_general</string> + <string name="help_context_protected_content">protected_content</string> + <string name="help_context_data_reduction">reduce_data_usage</string> + <string name="help_context_incognito_learn_more">chrome_incognito</string> + <string name="help_context_usage_reports">send_crash_report</string> + <string name="help_context_sad_tab">mobile_awsnap</string> + </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmark/BookmarksBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmark/BookmarksBridge.java index f0c1a97..34f842f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmark/BookmarksBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmark/BookmarksBridge.java
@@ -207,6 +207,29 @@ } /** + * Schedules a runnable to run after the bookmark model is loaded. If the + * model is already loaded, executes the runnable immediately. + * @return Whether the given runnable is executed synchronously. + */ + public boolean runAfterBookmarkModelLoaded(final Runnable runnable) { + if (isBookmarkModelLoaded()) { + runnable.run(); + return true; + } + addObserver(new BookmarkModelObserver() { + @Override + public void bookmarkModelLoaded() { + removeObserver(this); + runnable.run(); + } + @Override + public void bookmarkModelChanged() { + } + }); + return false; + } + + /** * @return A BookmarkItem instance for the given BookmarkId. * <code>null</code> if it doesn't exist. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OWNERS index e05460d..f1eeeb2f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OWNERS
@@ -1,3 +1,4 @@ -aurimas@chromium.org donnd@chromium.org pedrosimonetti@chromium.org + +per-file Overlay*=mdjones@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS index e05460d..0b21b49 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS
@@ -1,3 +1,2 @@ -aurimas@chromium.org donnd@chromium.org pedrosimonetti@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/OWNERS new file mode 100644 index 0000000..5ebdab3f --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/OWNERS
@@ -0,0 +1 @@ +mdjones@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java index f4975e3..052b44a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java
@@ -6,9 +6,11 @@ import android.content.Intent; import android.os.Bundle; +import android.text.TextUtils; import android.view.WindowManager; import org.chromium.chrome.R; +import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable; @@ -35,6 +37,10 @@ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); mSnackbarManager = new SnackbarManager(this); mBookmarkManager = new EnhancedBookmarkManager(this); + String url = getIntent().getDataString(); + if (TextUtils.isEmpty(url)) url = UrlConstants.BOOKMARKS_URL; + mBookmarkManager.updateForUrl(url); + setContentView(mBookmarkManager.getView()); EnhancedBookmarkUtils.setTaskDescriptionInDocumentMode(this, getString( OfflinePageBridge.isEnabled() ? R.string.offline_pages_saved_pages
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkBookmarkRow.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkBookmarkRow.java index 39b5647..25e2ba0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkBookmarkRow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkBookmarkRow.java
@@ -17,7 +17,6 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkItem; -import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkManager.UIState; import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageItem; @@ -60,16 +59,16 @@ public void onClick() { int launchLocation = -1; switch (mDelegate.getCurrentState()) { - case UIState.STATE_ALL_BOOKMARKS: + case EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS: launchLocation = LaunchLocation.ALL_ITEMS; break; - case UIState.STATE_FOLDER: + case EnhancedBookmarkUIState.STATE_FOLDER: launchLocation = LaunchLocation.FOLDER; break; - case UIState.STATE_FILTER: + case EnhancedBookmarkUIState.STATE_FILTER: launchLocation = LaunchLocation.FILTER; break; - case UIState.STATE_LOADING: + case EnhancedBookmarkUIState.STATE_LOADING: assert false : "The main content shouldn't be inflated if it's still loading"; break; @@ -94,7 +93,7 @@ private void updateOfflinePageSize(BookmarkId bookmarkId) { OfflinePageItem offlinePage = null; OfflinePageBridge bridge = mDelegate.getModel().getOfflinePageBridge(); - if (mDelegate.getCurrentState() == UIState.STATE_FILTER && bridge != null) { + if (mDelegate.getCurrentState() == EnhancedBookmarkUIState.STATE_FILTER && bridge != null) { offlinePage = bridge.getPageByBookmarkId(bookmarkId); } TextView textView = (TextView) findViewById(R.id.offline_page_size);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDelegate.java index a05b949..99d489d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDelegate.java
@@ -131,7 +131,7 @@ /** * @return Current UIState of Enhanced Bookmark main UI. If no mode is stored, - * {@link UIState#STATE_LOADING} is returned. + * {@link EnhancedBookmarkUIState#STATE_LOADING} is returned. */ int getCurrentState();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListView.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListView.java index b7775629..32aac97 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListView.java
@@ -13,7 +13,6 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkModelObserver; -import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkManager.UIState; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.components.bookmarks.BookmarkId; @@ -54,11 +53,11 @@ int currentState = mDelegate.getCurrentState(); boolean isConnected = OfflinePageUtils.isConnected(context); if (item.mType == EnhancedBookmarkDrawerListViewAdapter.TYPE_FILTER - && currentState != UIState.STATE_FILTER) { + && currentState != EnhancedBookmarkUIState.STATE_FILTER) { RecordHistogram.recordBooleanHistogram( "OfflinePages.Filter.OnlineWhenEntering", isConnected); } else if (item.mType != EnhancedBookmarkDrawerListViewAdapter.TYPE_FILTER - && currentState == UIState.STATE_FILTER) { + && currentState == EnhancedBookmarkUIState.STATE_FILTER) { RecordHistogram.recordBooleanHistogram( "OfflinePages.Filter.OnlineWhenLeaving", isConnected); } @@ -106,21 +105,22 @@ @Override public void onAllBookmarksStateSet() { mAdapter.updateList(); - setItemChecked(mAdapter.getItemPosition(UIState.STATE_ALL_BOOKMARKS, null), + setItemChecked(mAdapter.getItemPosition(EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS, null), true); } @Override public void onFolderStateSet(BookmarkId folder) { mAdapter.updateList(); - setItemChecked(mAdapter.getItemPosition(UIState.STATE_FOLDER, folder), + setItemChecked(mAdapter.getItemPosition(EnhancedBookmarkUIState.STATE_FOLDER, folder), true); } @Override public void onFilterStateSet(EnhancedBookmarkFilter filter) { mAdapter.updateList(); - setItemChecked(mAdapter.getItemPosition(UIState.STATE_FILTER, filter), true); + setItemChecked(mAdapter.getItemPosition(EnhancedBookmarkUIState.STATE_FILTER, filter), + true); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListViewAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListViewAdapter.java index 30ab95fb7..2fd4c83 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListViewAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkDrawerListViewAdapter.java
@@ -11,7 +11,6 @@ import android.widget.TextView; import org.chromium.chrome.R; -import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkManager.UIState; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.components.bookmarks.BookmarkId; @@ -204,9 +203,9 @@ * Get item position of the given mode. */ int getItemPosition(int state, Object modeDetail) { - if (state == UIState.STATE_ALL_BOOKMARKS) { + if (state == EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS) { return 0; - } else if (state == UIState.STATE_FOLDER) { + } else if (state == EnhancedBookmarkUIState.STATE_FOLDER) { Set<BookmarkId> topLevelFolderParents = new HashSet<>(); topLevelFolderParents.addAll(mDelegate.getModel().getTopLevelFolderParentIDs()); topLevelFolderParents.add(mDesktopNodeId); @@ -224,7 +223,7 @@ topFolderId = parentId; } return positionOfBookmarkId(topFolderId); - } else if (state == UIState.STATE_FILTER) { + } else if (state == EnhancedBookmarkUIState.STATE_FILTER) { EnhancedBookmarkFilter filter = (EnhancedBookmarkFilter) modeDetail; return positionOfItem(new Item(filter)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkFilter.java index e928298..861afb2eb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkFilter.java
@@ -8,5 +8,16 @@ * Possible filters for the enhanced bookmarks. */ enum EnhancedBookmarkFilter { - OFFLINE_PAGES + OFFLINE_PAGES("OFFLINE_PAGES"); + + /** + * An {@link EnhancedBookmarkFilter} can be persisted in URLs. To ensure the + * URLs are consistent, values should remain the same even after the enums + * are renamed. + */ + public final String value; + + private EnhancedBookmarkFilter(String value) { + this.value = value; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java index 183016b..39c00ab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java
@@ -16,7 +16,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkItem; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkModelObserver; -import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkManager.UIState; import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkPromoHeader.PromoHeaderShowingChangeListener; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; @@ -256,8 +255,8 @@ @Override public void onPromoHeaderShowingChanged(boolean isShowing) { - if (mDelegate.getCurrentState() != UIState.STATE_ALL_BOOKMARKS - && mDelegate.getCurrentState() != UIState.STATE_FOLDER) { + if (mDelegate.getCurrentState() != EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS + && mDelegate.getCurrentState() != EnhancedBookmarkUIState.STATE_FOLDER) { return; } @@ -284,7 +283,7 @@ @Override public void offlinePageDeleted(BookmarkId bookmarkId) { - if (mDelegate.getCurrentState() == UIState.STATE_FILTER) { + if (mDelegate.getCurrentState() == EnhancedBookmarkUIState.STATE_FILTER) { int deletedPosition = getPositionForBookmark(bookmarkId); if (deletedPosition >= 0) { removeItem(deletedPosition); @@ -360,17 +359,18 @@ private void updateHeader() { int currentUIState = mDelegate.getCurrentState(); - if (currentUIState == UIState.STATE_LOADING) return; + if (currentUIState == EnhancedBookmarkUIState.STATE_LOADING) return; mPromoHeaderSection.clear(); mOfflineStorageSection.clear(); - if (currentUIState == UIState.STATE_FILTER) { + if (currentUIState == EnhancedBookmarkUIState.STATE_FILTER) { if (mOfflineStorageHeader != null && mOfflineStorageHeader.shouldShow()) { mOfflineStorageSection.add(null); } } else { - assert currentUIState == UIState.STATE_ALL_BOOKMARKS - || currentUIState == UIState.STATE_FOLDER : "Unexpected UI state"; + assert currentUIState == EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS + || currentUIState == EnhancedBookmarkUIState.STATE_FOLDER + : "Unexpected UI state"; if (mPromoHeaderManager.shouldShow()) { mPromoHeaderSection.add(null); } @@ -378,7 +378,7 @@ } private void refreshOfflinePagesFilterView() { - if (mDelegate.getCurrentState() != UIState.STATE_FILTER) return; + if (mDelegate.getCurrentState() != EnhancedBookmarkUIState.STATE_FILTER) return; setBookmarks(null, mDelegate.getModel().getBookmarkIDsByFilter(EnhancedBookmarkFilter.OFFLINE_PAGES)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java index e0678dc..cd92109eb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
@@ -7,9 +7,8 @@ import android.app.Activity; import android.app.ActivityManager; import android.content.Context; -import android.preference.PreferenceManager; import android.support.v4.widget.DrawerLayout; -import android.util.Log; +import android.text.TextUtils; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -18,21 +17,15 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.ObserverList; import org.chromium.chrome.R; -import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkItem; import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkModelObserver; import org.chromium.chrome.browser.favicon.LargeIconBridge; -import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable; import org.chromium.components.bookmarks.BookmarkId; -import org.chromium.ui.base.DeviceFormFactor; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -45,7 +38,6 @@ * {@link EnhancedBookmarkActivity} (phone) and {@link EnhancedBookmarkPage} (tablet). */ public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate { - private static final String PREF_LAST_USED_URL = "enhanced_bookmark_last_used_url"; private static final int FAVICON_MAX_CACHE_SIZE_BYTES = 10 * 1024 * 1024; // 10MB private Activity mActivity; @@ -61,8 +53,9 @@ private ViewSwitcher mViewSwitcher; private DrawerLayout mDrawer; private EnhancedBookmarkDrawerListView mDrawerListView; - private final Stack<UIState> mStateStack = new Stack<>(); + private final Stack<EnhancedBookmarkUIState> mStateStack = new Stack<>(); private LargeIconBridge mLargeIconBridge; + private String mInitialUrl; private final BookmarkModelObserver mBookmarkModelObserver = new BookmarkModelObserver() { @@ -71,7 +64,7 @@ boolean isDoingExtensiveChanges) { // If the folder is removed in folder mode, show the parent folder or falls back to all // bookmarks mode. - if (getCurrentState() == UIState.STATE_FOLDER + if (getCurrentState() == EnhancedBookmarkUIState.STATE_FOLDER && node.getId().equals(mStateStack.peek().mFolder)) { if (mEnhancedBookmarksModel.getTopLevelFolderIDs(true, true).contains( node.getId())) { @@ -90,21 +83,29 @@ } @Override - public void bookmarkModelLoaded() { - initializeIfBookmarkModelLoaded(); - } - - @Override public void bookmarkModelChanged() { // If the folder no longer exists in folder mode, we need to fall back. Relying on the // default behavior by setting the folder mode again. - if (getCurrentState() == UIState.STATE_FOLDER) { + if (getCurrentState() == EnhancedBookmarkUIState.STATE_FOLDER) { setState(mStateStack.peek()); } clearSelection(); } }; + private final Runnable mModelLoadedRunnable = new Runnable() { + @Override + public void run() { + mSearchView.onEnhancedBookmarkDelegateInitialized(EnhancedBookmarkManager.this); + mDrawerListView.onEnhancedBookmarkDelegateInitialized(EnhancedBookmarkManager.this); + mContentView.onEnhancedBookmarkDelegateInitialized(EnhancedBookmarkManager.this); + if (!TextUtils.isEmpty(mInitialUrl)) { + setState(EnhancedBookmarkUIState.createStateFromUrl(mInitialUrl, + mEnhancedBookmarksModel)); + } + } + }; + /** * Creates an instance of {@link EnhancedBookmarkManager}. It also initializes resources, * bookmark models and jni bridges. @@ -123,7 +124,8 @@ ((SnackbarManageable) activity).getSnackbarManager()); mSearchView = (EnhancedBookmarkSearchView) getView().findViewById(R.id.eb_search_view); mEnhancedBookmarksModel.addObserver(mBookmarkModelObserver); - initializeIfBookmarkModelLoaded(); + initializeToLoadingState(); + mEnhancedBookmarksModel.runAfterBookmarkModelLoaded(mModelLoadedRunnable); // Load partner bookmarks explicitly. We load partner bookmarks in the deferred startup // code, but that might be executed much later. Especially on L, showing loading @@ -204,75 +206,33 @@ } /** - * Updates UI based on the new URL on tablet. If the bookmark model is not loaded yet, creates a - * temporary loading state carrying this url. This method is supposed to align with + * Updates UI based on the new URL. If the bookmark model is not loaded yet, cache the url and + * it will be picked up later when the model is loaded. This method is supposed to align with * {@link EnhancedBookmarkPage#updateForUrl(String)} * <p> * @param url The url to navigate to. */ public void updateForUrl(String url) { - if (mEnhancedBookmarksModel != null && mEnhancedBookmarksModel.isBookmarkModelLoaded()) { - setState(UIState.createStateFromUrl(url, mEnhancedBookmarksModel)); - } else { - // Note this does not guarantee to update the UI, as at this time the onCreateView() - // might not has even been called yet. - setState(UIState.createLoadingState(url)); - } - } + // Bookmark model is null if the manager has been destroyed. + if (mEnhancedBookmarksModel == null) return; - /** - * Initialization method that has 3 different behaviors based on whether bookmark model is - * loaded. If the bookmark model is not loaded yet, it pushes a loading state to backstack which - * contains the url from preference. If the model is loaded and the backstack is empty, it - * creates a state by fetching the last visited bookmark url stored in preference. If the - * bookmark model is loaded but backstack contains a pending loading state, it creates a new - * state by getting the url of the loading state and replace the previous loading state with the - * new normal state. - */ - private void initializeIfBookmarkModelLoaded() { if (mEnhancedBookmarksModel.isBookmarkModelLoaded()) { - mSearchView.onEnhancedBookmarkDelegateInitialized(this); - mDrawerListView.onEnhancedBookmarkDelegateInitialized(this); - mContentView.onEnhancedBookmarkDelegateInitialized(this); - if (mStateStack.isEmpty()) { - setState(UIState.createStateFromUrl(getUrlFromPreference(), - mEnhancedBookmarksModel)); - } else if (mStateStack.peek().mState == UIState.STATE_LOADING) { - String url = mStateStack.pop().mUrl; - setState(UIState.createStateFromUrl(url, mEnhancedBookmarksModel)); - } + setState(EnhancedBookmarkUIState.createStateFromUrl(url, mEnhancedBookmarksModel)); } else { - mContentView.showLoadingUi(); - mDrawerListView.showLoadingUi(); - mContentView.showLoadingUi(); - if (mStateStack.isEmpty() || mStateStack.peek().mState != UIState.STATE_LOADING) { - setState(UIState.createLoadingState(getUrlFromPreference())); - } else if (!mStateStack.isEmpty()) { - // Refresh the UI. This is needed because on tablet, updateForUrl might set up - // loading state too early and at that time all UI components are not created yet. - // Therefore we need to set the previous loading state once again to trigger all UI - // updates. - setState(mStateStack.pop()); - } + mInitialUrl = url; } } /** - * Saves url to preference. Note this method should be used after the main view is attached to - * an activity. + * Puts all UI elements to loading state. This state might be overridden synchronously by + * {@link #updateForUrl(String)}, if the bookmark model is already loaded. */ - private void saveUrlToPreference(String url) { - PreferenceManager.getDefaultSharedPreferences(mActivity).edit() - .putString(PREF_LAST_USED_URL, url).apply(); - } - - /** - * Fetches url to preference. Note this method should be used after the main view is attached to - * an activity. - */ - private String getUrlFromPreference() { - return PreferenceManager.getDefaultSharedPreferences(mActivity).getString( - PREF_LAST_USED_URL, UrlConstants.BOOKMARKS_URL); + private void initializeToLoadingState() { + mContentView.showLoadingUi(); + mDrawerListView.showLoadingUi(); + mContentView.showLoadingUi(); + assert mStateStack.isEmpty(); + setState(EnhancedBookmarkUIState.createLoadingState()); } /** @@ -288,41 +248,30 @@ * and back button are not controlled by the manager: the tab handles back key and backstack * navigation. */ - private void setState(UIState state) { + private void setState(EnhancedBookmarkUIState state) { if (!state.isValid(mEnhancedBookmarksModel)) { - state = UIState.createAllBookmarksState(mEnhancedBookmarksModel); + state = EnhancedBookmarkUIState.createAllBookmarksState(mEnhancedBookmarksModel); } - boolean saveUrl = true; - if (mStateStack.isEmpty()) { - // When offline page feature is enabled, show offline filter view if there is offline - // page and there is no network connection. - if (mEnhancedBookmarksModel.getOfflinePageBridge() != null - && !mEnhancedBookmarksModel.getOfflinePageBridge().getAllPages().isEmpty() - && !OfflinePageUtils.isConnected(mActivity.getApplicationContext()) - && !DeviceFormFactor.isTablet(mActivity.getApplicationContext())) { - UIState filterState = UIState.createFilterState( - EnhancedBookmarkFilter.OFFLINE_PAGES, mEnhancedBookmarksModel); - if (state.mState != UIState.STATE_LOADING) { - state = filterState; - } else { - state.mUrl = filterState.mUrl; - } - // Showing offline filter view is just a temporary thing and it will not be saved - // to the preference. - saveUrl = false; - } - } else { - if (mStateStack.peek().equals(state)) return; - if (mStateStack.peek().mState == UIState.STATE_LOADING) { - mStateStack.pop(); - } + + if (!mStateStack.isEmpty() && mStateStack.peek().equals(state)) return; + + // The loading state is not persisted in history stack and once we have a valid state it + // shall be removed. + if (!mStateStack.isEmpty() + && mStateStack.peek().mState == EnhancedBookmarkUIState.STATE_LOADING) { + mStateStack.pop(); } mStateStack.push(state); - if (state.mState != UIState.STATE_LOADING) { + + if (state.mState != EnhancedBookmarkUIState.STATE_LOADING) { // Loading state may be pushed to the stack but should never be stored in preferences. - if (saveUrl) saveUrlToPreference(state.mUrl); + if (state.mShouldPersist) { + EnhancedBookmarkUtils.setLastUsedUrl(mActivity, state.mUrl); + } // If a loading state is replaced by another loading state, do not notify this change. - if (mUrlChangeListener != null) mUrlChangeListener.onBookmarkUIStateChange(state.mUrl); + if (mUrlChangeListener != null) { + mUrlChangeListener.onBookmarkUIStateChange(state.mUrl); + } } clearSelection(); @@ -337,18 +286,18 @@ @Override public void openFolder(BookmarkId folder) { closeSearchUI(); - setState(UIState.createFolderState(folder, mEnhancedBookmarksModel)); + setState(EnhancedBookmarkUIState.createFolderState(folder, mEnhancedBookmarksModel)); } @Override public void openAllBookmarks() { closeSearchUI(); - setState(UIState.createAllBookmarksState(mEnhancedBookmarksModel)); + setState(EnhancedBookmarkUIState.createAllBookmarksState(mEnhancedBookmarksModel)); } @Override public void openFilter(EnhancedBookmarkFilter filter) { - setState(UIState.createFilterState(filter, mEnhancedBookmarksModel)); + setState(EnhancedBookmarkUIState.createFilterState(filter, mEnhancedBookmarksModel)); } @Override @@ -391,18 +340,18 @@ public void notifyStateChange(EnhancedBookmarkUIObserver observer) { int state = getCurrentState(); switch (state) { - case UIState.STATE_ALL_BOOKMARKS: + case EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS: observer.onAllBookmarksStateSet(); break; - case UIState.STATE_FOLDER: + case EnhancedBookmarkUIState.STATE_FOLDER: observer.onFolderStateSet(mStateStack.peek().mFolder); break; - case UIState.STATE_LOADING: + case EnhancedBookmarkUIState.STATE_LOADING: // In loading state, onEnhancedBookmarkDelegateInitialized() is not called for all // UIObservers, which means that there will be no observers at the time. Do nothing. assert mUIObservers.isEmpty(); break; - case UIState.STATE_FILTER: + case EnhancedBookmarkUIState.STATE_FILTER: observer.onFilterStateSet(mStateStack.peek().mFilter); break; default: @@ -466,7 +415,7 @@ @Override public int getCurrentState() { - if (mStateStack.isEmpty()) return UIState.STATE_LOADING; + if (mStateStack.isEmpty()) return EnhancedBookmarkUIState.STATE_LOADING; return mStateStack.peek().mState; } @@ -479,132 +428,4 @@ public SnackbarManager getSnackbarManager() { return ((SnackbarManageable) mActivity).getSnackbarManager(); } - - /** - * Internal state that represents a url. Note every state needs to have a _valid_ url. For - * loading state, {@link #mUrl} indicates the target to open after the bookmark model is loaded. - */ - static class UIState { - private static final int STATE_INVALID = 0; - static final int STATE_LOADING = 1; - static final int STATE_ALL_BOOKMARKS = 2; - static final int STATE_FOLDER = 3; - static final int STATE_FILTER = 4; - - private static final String TAG = "UIState"; - private static final String URL_CHARSET = "UTF-8"; - /** - * One of the STATE_* constants. - */ - private int mState; - private String mUrl; - private BookmarkId mFolder; - private EnhancedBookmarkFilter mFilter; - - private static UIState createLoadingState(String url) { - UIState state = new UIState(); - state.mUrl = url; - state.mState = STATE_LOADING; - return state; - } - - private static UIState createAllBookmarksState(EnhancedBookmarksModel bookmarkModel) { - return createStateFromUrl(UrlConstants.BOOKMARKS_URL, bookmarkModel); - } - - private static UIState createFolderState(BookmarkId folder, - EnhancedBookmarksModel bookmarkModel) { - return createStateFromUrl(UrlConstants.BOOKMARKS_FOLDER_URL + folder.toString(), - bookmarkModel); - } - - private static UIState createFilterState( - EnhancedBookmarkFilter filter, EnhancedBookmarksModel bookmarkModel) { - return createStateFromUrl( - UrlConstants.BOOKMARKS_FILTER_URL + filter.toString(), bookmarkModel); - } - - /** - * @return A state corresponding to the url. If the url is not valid, return all_bookmarks. - */ - private static UIState createStateFromUrl(String url, - EnhancedBookmarksModel bookmarkModel) { - UIState state = new UIState(); - state.mState = STATE_INVALID; - state.mUrl = url; - - if (url.equals(UrlConstants.BOOKMARKS_URL)) { - state.mState = STATE_ALL_BOOKMARKS; - } else if (url.startsWith(UrlConstants.BOOKMARKS_FOLDER_URL)) { - String suffix = decodeSuffix(url, UrlConstants.BOOKMARKS_FOLDER_URL); - if (!suffix.isEmpty()) { - state.mFolder = BookmarkId.getBookmarkIdFromString(suffix); - state.mState = STATE_FOLDER; - } - } else if (url.startsWith(UrlConstants.BOOKMARKS_FILTER_URL)) { - String suffix = decodeSuffix(url, UrlConstants.BOOKMARKS_FILTER_URL); - if (!suffix.isEmpty()) { - state.mState = STATE_FILTER; - state.mFilter = EnhancedBookmarkFilter.valueOf(suffix); - } - } - - if (!state.isValid(bookmarkModel)) { - state.mState = STATE_ALL_BOOKMARKS; - state.mUrl = UrlConstants.BOOKMARKS_URL; - } - - return state; - } - - private UIState() { - } - - /** - * @return Whether this state is valid. - */ - private boolean isValid(EnhancedBookmarksModel bookmarkModel) { - if (mUrl == null || mState == STATE_INVALID) return false; - - if (mState == STATE_FOLDER) { - if (mFolder == null) return false; - - return bookmarkModel.doesBookmarkExist(mFolder) - && !mFolder.equals(bookmarkModel.getRootFolderId()); - } - - return true; - } - - private static String decodeSuffix(String url, String prefix) { - String suffix = url.substring(prefix.length()); - try { - suffix = URLDecoder.decode(suffix, URL_CHARSET); - } catch (UnsupportedEncodingException e) { - Log.w(TAG, "Bookmark URL parsing failed. " + URL_CHARSET + " not supported."); - } - return suffix; - } - - private static String encodeUrl(String prefix, String suffix) { - try { - suffix = URLEncoder.encode(suffix, URL_CHARSET); - } catch (UnsupportedEncodingException e) { - Log.w(TAG, "Bookmark URL parsing failed. " + URL_CHARSET + " not supported."); - } - return prefix + suffix; - } - - @Override - public int hashCode() { - return 31 * mUrl.hashCode() + mState; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof UIState)) return false; - UIState other = (UIState) obj; - return mState == other.mState && mUrl.equals(other.mUrl); - } - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPage.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPage.java index f30da93..889be8c9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPage.java
@@ -29,6 +29,7 @@ private final int mBackgroundColor; private final int mThemeColor; private EnhancedBookmarkManager mManager; + private String mCurrentUrl; /** * Create a new instance of an enhanced bookmark page. @@ -97,6 +98,7 @@ @Override public void updateForUrl(String url) { + mCurrentUrl = url; mManager.updateForUrl(url); } @@ -108,6 +110,7 @@ @Override public void onBookmarkUIStateChange(String url) { + if (url.equals(mCurrentUrl)) return; mTab.loadUrl(new LoadUrlParams(url)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkRecyclerView.java index 90e3d06..32c94bd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkRecyclerView.java
@@ -166,4 +166,9 @@ } } } + + @VisibleForTesting + public EnhancedBookmarkDelegate getDelegateForTesting() { + return mDelegate; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUIState.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUIState.java new file mode 100644 index 0000000..20dbdf0d --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUIState.java
@@ -0,0 +1,158 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.enhancedbookmarks; + +import android.net.Uri; +import android.text.TextUtils; + +import org.chromium.chrome.browser.UrlConstants; +import org.chromium.components.bookmarks.BookmarkId; + +/** + * A class representing the UI state of the {@link EnhancedBookmarkManager}. All + * states can be uniquely identified by a URL. + */ +class EnhancedBookmarkUIState { + static final String URI_PERSIST_QUERY_NAME = "persist"; + + static final int STATE_LOADING = 1; + static final int STATE_ALL_BOOKMARKS = 2; + static final int STATE_FOLDER = 3; + static final int STATE_FILTER = 4; + private static final int STATE_INVALID = 0; + + /** + * One of the STATE_* constants. + */ + int mState; + String mUrl; + /** Whether this state should be persisted as user's last location. */ + boolean mShouldPersist = true; + BookmarkId mFolder; + EnhancedBookmarkFilter mFilter; + + static EnhancedBookmarkUIState createLoadingState() { + EnhancedBookmarkUIState state = new EnhancedBookmarkUIState(); + state.mState = STATE_LOADING; + state.mShouldPersist = false; + state.mUrl = ""; + return state; + } + + static EnhancedBookmarkUIState createAllBookmarksState(EnhancedBookmarksModel bookmarkModel) { + return createStateFromUrl(Uri.parse(UrlConstants.BOOKMARKS_URL), bookmarkModel); + } + + static EnhancedBookmarkUIState createFolderState(BookmarkId folder, + EnhancedBookmarksModel bookmarkModel) { + return createStateFromUrl(createFolderUrl(folder), bookmarkModel); + } + + static EnhancedBookmarkUIState createFilterState( + EnhancedBookmarkFilter filter, EnhancedBookmarksModel bookmarkModel) { + return createStateFromUrl(createFilterUrl(filter, true), bookmarkModel); + } + + /** + * @see #createStateFromUrl(Uri, EnhancedBookmarksModel) + */ + static EnhancedBookmarkUIState createStateFromUrl(String url, + EnhancedBookmarksModel bookmarkModel) { + return createStateFromUrl(Uri.parse(url), bookmarkModel); + } + + /** + * @return A state corresponding to the URI object. If the URI is not valid, + * return all_bookmarks. + */ + static EnhancedBookmarkUIState createStateFromUrl(Uri uri, + EnhancedBookmarksModel bookmarkModel) { + EnhancedBookmarkUIState state = new EnhancedBookmarkUIState(); + state.mState = STATE_INVALID; + state.mUrl = uri.toString(); + state.mShouldPersist = shouldPersist(uri); + + if (state.mUrl.equals(UrlConstants.BOOKMARKS_URL)) { + state.mState = STATE_ALL_BOOKMARKS; + } else if (state.mUrl.startsWith(UrlConstants.BOOKMARKS_FOLDER_URL)) { + String path = uri.getLastPathSegment(); + if (!path.isEmpty()) { + state.mFolder = BookmarkId.getBookmarkIdFromString(path); + state.mState = STATE_FOLDER; + } + } else if (state.mUrl.startsWith(UrlConstants.BOOKMARKS_FILTER_URL)) { + String path = uri.getLastPathSegment(); + if (!path.isEmpty()) { + state.mState = STATE_FILTER; + state.mFilter = EnhancedBookmarkFilter.valueOf(path); + } + } + + if (!state.isValid(bookmarkModel)) { + state.mState = STATE_ALL_BOOKMARKS; + state.mUrl = UrlConstants.BOOKMARKS_URL; + } + + return state; + } + + static Uri createFolderUrl(BookmarkId folderId) { + return createUrl(UrlConstants.BOOKMARKS_FOLDER_URL, folderId.toString(), true); + } + + static Uri createFilterUrl(EnhancedBookmarkFilter filter, boolean shouldPersist) { + return createUrl(UrlConstants.BOOKMARKS_FILTER_URL, filter.value, shouldPersist); + } + + /** + * Encodes the path and appends it to the base url. A simple appending + * does not work because there might be spaces in suffix. + * @param shouldPersist Whether this url should be saved to preferences as + * user's last location. + */ + private static Uri createUrl(String baseUrl, String pathSuffix, boolean shouldPersist) { + Uri.Builder builder = Uri.parse(baseUrl).buildUpon(); + builder.appendPath(pathSuffix); + if (!shouldPersist) { + builder.appendQueryParameter(URI_PERSIST_QUERY_NAME, "0"); + } + return builder.build(); + } + + private static boolean shouldPersist(Uri uri) { + String queryString = uri.getQueryParameter(URI_PERSIST_QUERY_NAME); + return !("0".equals(queryString)); + } + + private EnhancedBookmarkUIState() {} + + @Override + public int hashCode() { + return 31 * mUrl.hashCode() + mState; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof EnhancedBookmarkUIState)) return false; + EnhancedBookmarkUIState other = (EnhancedBookmarkUIState) obj; + return mState == other.mState && TextUtils.equals(mUrl, other.mUrl); + } + + /** + * @return Whether this state is valid. + */ + boolean isValid(EnhancedBookmarksModel bookmarkModel) { + if (mUrl == null || mState == STATE_INVALID) return false; + + if (mState == STATE_FOLDER) { + return mFolder != null && bookmarkModel.doesBookmarkExist(mFolder) + && !mFolder.equals(bookmarkModel.getRootFolderId()); + } + + if (mState == STATE_FILTER && mFilter == null) return false; + + return true; + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java index 62873dfa..16dbe7e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java
@@ -10,11 +10,12 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; -import android.os.Bundle; +import android.preference.PreferenceManager; import android.provider.Browser; import android.text.TextUtils; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; @@ -22,7 +23,6 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.bookmark.BookmarksBridge; -import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkItem; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarksModel.AddBookmarkCallback; import org.chromium.chrome.browser.favicon.FaviconHelper; @@ -38,7 +38,6 @@ import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.FeatureUtilities; -import org.chromium.chrome.browser.util.MathUtils; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.bookmarks.BookmarkType; import org.chromium.content_public.browser.WebContents; @@ -48,18 +47,7 @@ * A class holding static util functions for enhanced bookmark. */ public class EnhancedBookmarkUtils { - - private static final String BOOKMARK_SAVE_NAME = "SaveBookmark"; - private static final int[] DEFAULT_BACKGROUND_COLORS = { - 0xFFE64A19, - 0xFFF09300, - 0xFFAFB42B, - 0xFF689F38, - 0xFF0B8043, - 0xFF0097A7, - 0xFF7B1FA2, - 0xFFC2185B - }; + private static final String PREF_LAST_USED_URL = "enhanced_bookmark_last_used_url"; /** * @return True if enhanced bookmark feature is enabled. @@ -258,6 +246,19 @@ } /** + * Gets whether bookmark manager should load offline page initially. + */ + private static boolean shouldShowOfflinePageAtFirst(EnhancedBookmarksModel model, + Context context) { + OfflinePageBridge bridge = model.getOfflinePageBridge(); + if (bridge == null || bridge.getAllPages().isEmpty() + || OfflinePageUtils.isConnected(context)) { + return false; + } + return true; + } + + /** * Shows enhanced bookmark main UI, if it is turned on. Does nothing if it is turned off. * @return True if enhanced bookmark is on, false otherwise. */ @@ -265,15 +266,57 @@ if (!isEnhancedBookmarkEnabled()) { return false; } + + String url = getFirstUrlToLoad(activity); + if (DeviceFormFactor.isTablet(activity)) { - openUrl(activity, UrlConstants.BOOKMARKS_URL); + openUrl(activity, url); } else { - activity.startActivity(new Intent(activity, EnhancedBookmarkActivity.class)); + Intent intent = new Intent(activity, EnhancedBookmarkActivity.class); + intent.setData(Uri.parse(url)); + activity.startActivity(intent); } return true; } /** + * The initial url the bookmark manager shows depends on offline page status and some + * experiments we run. + */ + private static String getFirstUrlToLoad(Activity activity) { + EnhancedBookmarksModel model = new EnhancedBookmarksModel(); + try { + if (shouldShowOfflinePageAtFirst(model, activity)) { + return EnhancedBookmarkUIState.createFilterUrl(EnhancedBookmarkFilter.OFFLINE_PAGES, + false).toString(); + } + String lastUsedUrl = getLastUsedUrl(activity); + if (!TextUtils.isEmpty(lastUsedUrl)) return lastUsedUrl; + return UrlConstants.BOOKMARKS_URL; + } finally { + model.destroy(); + } + } + + /** + * Saves the last used url to preference. The saved url will be later queried by + * {@link #getLastUsedUrl(Context)} + */ + static void setLastUsedUrl(Context context, String url) { + PreferenceManager.getDefaultSharedPreferences(context).edit() + .putString(PREF_LAST_USED_URL, url).apply(); + } + + /** + * Fetches url representing the user's state last time they close the bookmark manager. + */ + @VisibleForTesting + static String getLastUsedUrl(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getString( + PREF_LAST_USED_URL, UrlConstants.BOOKMARKS_URL); + } + + /** * Starts an {@link EnhancedBookmarkEditActivity} for the given {@link BookmarkId}. */ public static void startEditActivity( @@ -292,37 +335,6 @@ } /** - * Generate color based on bookmarked url's hash code. Same color will - * always be returned given same bookmark item. - * - * @param item bookmark the color represents for - * @return int for the generated color - */ - public static int generateBackgroundColor(BookmarkItem item) { - int normalizedIndex = MathUtils.positiveModulo(item.getUrl().hashCode(), - DEFAULT_BACKGROUND_COLORS.length); - return DEFAULT_BACKGROUND_COLORS[normalizedIndex]; - } - - /** - * Save the bookmark in bundle to save state of a fragment/activity. - * @param bundle Argument holder or savedInstanceState of the fragment/activity. - * @param bookmark The bookmark to save. - */ - public static void saveBookmarkIdToBundle(Bundle bundle, BookmarkId bookmark) { - bundle.putString(BOOKMARK_SAVE_NAME, bookmark.toString()); - } - - /** - * Retrieve the bookmark previously saved in the arguments bundle. - * @param bundle Argument holder or savedInstanceState of the fragment/activity. - * @return The ID of the bookmark to retrieve. - */ - public static BookmarkId getBookmarkIdFromBundle(Bundle bundle) { - return BookmarkId.getBookmarkIdFromString(bundle.getString(BOOKMARK_SAVE_NAME)); - } - - /** * Opens a bookmark depending on connection status and reports UMA. * @param model Enhanced bookmarks model to manage the bookmark. * @param activity Activity requesting to open the bookmark.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java index cbdbba1..a4afa8a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -110,18 +110,18 @@ contentSettingsType = mContentSettingsToPermissionsMap.keyAt(i); } } - switch (contentSettingsType) { - case ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION: - return R.string.infobar_missing_location_permission_text; - case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: - return R.string.infobar_missing_microphone_permission_text; - case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: - return R.string.infobar_missing_camera_permission_text; - default: - assert false; - return R.string.infobar_missing_multiple_permissions_text; + if (contentSettingsType == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION) { + return R.string.infobar_missing_location_permission_text; } + if (contentSettingsType == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) { + return R.string.infobar_missing_microphone_permission_text; + } + if (contentSettingsType == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { + return R.string.infobar_missing_camera_permission_text; + } + assert false : "Unexpected content setting type received: " + contentSettingsType; + return R.string.infobar_missing_multiple_permissions_text; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 1039c2a9..d167031 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -36,6 +36,8 @@ import org.chromium.base.CommandLine; import org.chromium.base.VisibleForTesting; +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; @@ -322,8 +324,24 @@ if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_NTP_SNIPPETS)) { mSnippetsView = (RecyclerView) findViewById(R.id.snippets_card_list); mSnippetsView.setVisibility(View.VISIBLE); + RecordHistogram.recordEnumeratedHistogram(SnippetsManager.SNIPPETS_STATE_HISTOGRAM, + SnippetsManager.SNIPPETS_SHOWN, SnippetsManager.NUM_SNIPPETS_ACTIONS); mSnippetsView.setLayoutManager(new LinearLayoutManager(getContext())); mSnippetsManager = new SnippetsManager(mManager, mSnippetsView); + mSnippetsView.addOnScrollListener(new RecyclerView.OnScrollListener() { + private boolean mScrolledOnce = false; + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState != RecyclerView.SCROLL_STATE_DRAGGING) return; + RecordUserAction.record("MobileNTP.Snippets.Scrolled"); + if (mScrolledOnce) return; + mScrolledOnce = true; + RecordHistogram.recordEnumeratedHistogram( + SnippetsManager.SNIPPETS_STATE_HISTOGRAM, + SnippetsManager.SNIPPETS_SCROLLED, + SnippetsManager.NUM_SNIPPETS_ACTIONS); + } + }); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java index d9e3708..3c99bbe3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
@@ -11,6 +11,8 @@ import android.widget.ImageView; import android.widget.TextView; +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetArticle; import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetListItem; @@ -25,6 +27,7 @@ public TextView mReadMoreLinkTextView; public ImageView mThumbnailView; public String mUrl; + public int mPosition; /** * Creates the CardView object to display snippets information @@ -56,8 +59,23 @@ @Override public void onClick(View v) { loadUrl(mUrl); + RecordUserAction.record("MobileNTP.Snippets.Click"); + RecordHistogram.recordSparseSlowlyHistogram( + "NewTabPage.Snippets.CardClicked", mPosition); + RecordHistogram.recordEnumeratedHistogram(SnippetsManager.SNIPPETS_STATE_HISTOGRAM, + SnippetsManager.SNIPPETS_CLICKED, SnippetsManager.NUM_SNIPPETS_ACTIONS); } }); + cardView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + RecordHistogram.recordSparseSlowlyHistogram( + "NewTabPage.Snippets.CardShown", mPosition); + } + + @Override + public void onViewDetachedFromWindow(View v) {} + }); } @Override @@ -65,9 +83,15 @@ // Toggle visibility of snippet text int visibility = (mArticleSnippetTextView.getVisibility() == View.GONE) ? View.VISIBLE : View.GONE; - mArticleSnippetTextView.setVisibility(visibility); mReadMoreLinkTextView.setVisibility(visibility); + + String action = visibility == View.VISIBLE ? "MobileNTP.Snippets.ShowMore" + : "MobileNTP.Snippets.ShowLess"; + String histogram = visibility == View.VISIBLE ? "NewTabPage.Snippets.CardExpanded" + : "NewTabPage.Snippets.CardHidden"; + RecordUserAction.record(action); + RecordHistogram.recordSparseSlowlyHistogram(histogram, mPosition); } @Override @@ -78,6 +102,7 @@ mPublisherTextView.setText(item.mPublisher); mArticleSnippetTextView.setText(item.mSnippet); mUrl = item.mUrl; + mPosition = item.mPosition; item.setThumbnailOnView(mThumbnailView); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java index b8378b8..eb90180 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
@@ -13,6 +13,7 @@ import org.chromium.base.Log; import org.chromium.base.StreamUtil; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; import java.io.File; @@ -38,6 +39,16 @@ */ public static final int SNIPPET_ITEM_TYPE_SNIPPET = 2; + /** + * Enum values for recording {@code SNIPPETS_STATE_HISTOGRAM} histogram. + * Stored here as it is recorded in multiple places. + */ + public static final int SNIPPETS_SHOWN = 0; + public static final int SNIPPETS_SCROLLED = 1; + public static final int SNIPPETS_CLICKED = 2; + public static final int NUM_SNIPPETS_ACTIONS = 3; + public static final String SNIPPETS_STATE_HISTOGRAM = "NewTabPage.Snippets.Interactions"; + private NewTabPageManager mNewTabPageManager; private SnippetsAdapter mDataAdapter; @@ -78,6 +89,7 @@ public final String mSnippet; public final String mUrl; public final String mThumbnailPath; + public final int mPosition; private ThumbnailRenderingTask mThumbnailRenderingTask; @@ -104,13 +116,14 @@ } } - public SnippetArticle( - String title, String publisher, String snippet, String url, String thumbnailPath) { + public SnippetArticle(String title, String publisher, String snippet, String url, + String thumbnailPath, int position) { mTitle = title; mPublisher = publisher; mSnippet = snippet; mUrl = url; mThumbnailPath = thumbnailPath; + mPosition = position; } @Override @@ -134,6 +147,8 @@ } private class ReadFileTask extends AsyncTask<Void, Void, List<SnippetListItem>> { + private int mNumArticles; + @Override protected List<SnippetListItem> doInBackground(Void... params) { FileInputStream fis = null; @@ -170,11 +185,14 @@ private List<SnippetListItem> readRecommendationsArray(JsonReader reader) throws IOException { List<SnippetListItem> listSnippetItems = new ArrayList<SnippetListItem>(); + mNumArticles = 0; reader.beginArray(); while (reader.hasNext()) { readSnippetGroup(listSnippetItems, reader); } reader.endArray(); + RecordHistogram.recordSparseSlowlyHistogram( + "NewTabPage.Snippets.NumArticles", mNumArticles); return listSnippetItems; } @@ -227,7 +245,7 @@ } reader.endObject(); return new SnippetsManager.SnippetArticle( - headline, publisher, snippets, url, thumbnail); + headline, publisher, snippets, url, thumbnail, mNumArticles++); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java index 4bd5637..50029d1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java
@@ -127,7 +127,7 @@ if (responseCode > 0) { httpErr = ", HTTP " + responseCode; } - Log.e(TAG, "Error making request to PWS%s", httpErr, e); + Log.e(TAG, "Error making request to PWS%s", httpErr); resolveScanCallback.onPwsResults(new ArrayList<PwsResult>()); } }; @@ -171,7 +171,7 @@ if (responseCode > 0) { httpErr = ", HTTP " + responseCode; } - Log.e(TAG, "Error requesting icon%s", httpErr, e); + Log.e(TAG, "Error requesting icon%s", httpErr); } };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java index 04602a2..d5caaa1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -357,19 +357,19 @@ } private boolean showWarningFor(int type) { - switch (type) { - case ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION: - if (mSite.getGeolocationPermission() == null) return false; - break; - case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: - if (mSite.getCameraPermission() == null) return false; - break; - case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: - if (mSite.getMicrophonePermission() == null) return false; - break; - default: - return false; + ContentSetting setting = null; + if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION) { + setting = mSite.getGeolocationPermission(); + } else if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { + setting = mSite.getCameraPermission(); + } else if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) { + setting = mSite.getMicrophonePermission(); } + + if (setting == null) { + return false; + } + SiteSettingsCategory category = SiteSettingsCategory.fromContentSettingsType(type); return category.showPermissionBlockedMessage(getActivity()); }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 76ae5a0..006c224e 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2269,58 +2269,6 @@ Close tab </message> - <!-- Help and Feedback - These constants should be in sync with the context names on go/mobilehelprecs. - If the context ID cannot be found, the default help page will be shown to the user.--> - <message name="IDS_HELP_CONTEXT_NEW_TAB" translateable="false"> - mobile_new_tab - </message> - <message name="IDS_HELP_CONTEXT_SEARCH_RESULTS" translateable="false"> - mobile_search_results - </message> - <message name="IDS_HELP_CONTEXT_WEBPAGE" translateable="false"> - mobile_webpage - </message> - <message name="IDS_HELP_CONTEXT_SETTINGS" translateable="false"> - mobile_settings - </message> - <message name="IDS_HELP_CONTEXT_INCOGNITO" translateable="false"> - mobile_incognito - </message> - <message name="IDS_HELP_CONTEXT_BOOKMARKS" translateable="false"> - mobile_bookmarks - </message> - <message name="IDS_HELP_CONTEXT_HISTORY" translateable="false"> - mobile_history - </message> - <message name="IDS_HELP_CONTEXT_ERROR" translateable="false"> - mobile_error - </message> - <message name="IDS_HELP_CONTEXT_PRIVACY" translateable="false"> - mobile_privacy - </message> - <message name="IDS_HELP_CONTEXT_TRANSLATE" translateable="false"> - mobile_translate - </message> - <message name="IDS_HELP_CONTEXT_GENERAL" translateable="false"> - mobile_general - </message> - <message name="IDS_HELP_CONTEXT_PROTECTED_CONTENT" translateable="false"> - protected_content - </message> - <message name="IDS_HELP_CONTEXT_DATA_REDUCTION" translateable="false"> - reduce_data_usage - </message> - <message name="IDS_HELP_CONTEXT_INCOGNITO_LEARN_MORE" translateable="false"> - chrome_incognito - </message> - <message name="IDS_HELP_CONTEXT_USAGE_REPORTS" translateable="false"> - send_crash_report - </message> - <message name="IDS_HELP_CONTEXT_SAD_TAB" translateable="false"> - mobile_awsnap - </message> - <!-- Client certificate selection failure strings. --> <message name="IDS_CLIENT_CERT_UNSUPPORTED_TITLE" desc="Title of a dialog box for when the operating system does not support client SSL certificate selection"> Unable to select certificate.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkTest.java index 01deb04..949b99d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkTest.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.enhancedbookmarks; +import android.content.Intent; +import android.net.Uri; import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; import android.view.View; @@ -48,7 +50,7 @@ private static final String TEST_PAGE_TITLE = "The Google"; private EnhancedBookmarksModel mBookmarkModel; - private EnhancedBookmarkRecyclerView mItemsContainer; + protected EnhancedBookmarkRecyclerView mItemsContainer; @Override public void startMainActivity() throws InterruptedException { @@ -105,6 +107,28 @@ } } + private void openBookmarkManager(final String url) throws InterruptedException { + if (DeviceFormFactor.isTablet(getActivity())) { + loadUrl(url); + mItemsContainer = (EnhancedBookmarkRecyclerView) getActivity().findViewById( + R.id.eb_items_container); + } else { + // phone + EnhancedBookmarkActivity activity = ActivityUtils.waitForActivity(getInstrumentation(), + EnhancedBookmarkActivity.class, new Runnable() { + @Override + public void run() { + Intent intent = new Intent(getActivity(), + EnhancedBookmarkActivity.class); + intent.setData(Uri.parse(url)); + getActivity().startActivity(intent); + } + }); + mItemsContainer = (EnhancedBookmarkRecyclerView) activity.findViewById( + R.id.eb_items_container); + } + } + private boolean isItemPresentInBookmarkList(final String expectedTitle) { return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { @Override @@ -166,4 +190,56 @@ }); assertEquals(TEST_PAGE_TITLE, getActivity().getActivityTab().getTitle()); } + + @SmallTest + public void testUrlComposition() { + BookmarkId mobileId = mBookmarkModel.getMobileFolderId(); + BookmarkId bookmarkBarId = mBookmarkModel.getDesktopFolderId(); + BookmarkId otherId = mBookmarkModel.getOtherFolderId(); + assertEquals("chrome-native://bookmarks/folder/" + mobileId, + EnhancedBookmarkUIState.createFolderUrl(mobileId).toString()); + assertEquals("chrome-native://bookmarks/folder/" + bookmarkBarId, + EnhancedBookmarkUIState.createFolderUrl(bookmarkBarId).toString()); + assertEquals("chrome-native://bookmarks/folder/" + otherId, + EnhancedBookmarkUIState.createFolderUrl(otherId).toString()); + + assertEquals("chrome-native://bookmarks/filter/OFFLINE_PAGES", EnhancedBookmarkUIState + .createFilterUrl(EnhancedBookmarkFilter.OFFLINE_PAGES, true).toString()); + assertEquals( + "chrome-native://bookmarks/filter/OFFLINE_PAGES?persist=0", + EnhancedBookmarkUIState.createFilterUrl(EnhancedBookmarkFilter.OFFLINE_PAGES, + false).toString()); + } + + @SmallTest + public void testOpenBookmarkManager() throws InterruptedException { + openBookmarkManager(); + EnhancedBookmarkDelegate delegate = mItemsContainer.getDelegateForTesting(); + assertEquals(EnhancedBookmarkUIState.STATE_ALL_BOOKMARKS, delegate.getCurrentState()); + assertEquals(UrlConstants.BOOKMARKS_URL, + EnhancedBookmarkUtils.getLastUsedUrl(getActivity())); + } + + @SmallTest + @CommandLineFlags.Add(ChromeSwitches.ENABLE_OFFLINE_PAGES) + public void testOpenBookmarkManagerInOfflinePagePersist() throws InterruptedException { + EnhancedBookmarkUtils.setLastUsedUrl(getActivity(), UrlConstants.BOOKMARKS_URL); + String url = "chrome-native://bookmarks/filter/OFFLINE_PAGES"; + openBookmarkManager(url); + EnhancedBookmarkDelegate delegate = mItemsContainer.getDelegateForTesting(); + assertEquals(EnhancedBookmarkUIState.STATE_FILTER, delegate.getCurrentState()); + assertEquals(url, EnhancedBookmarkUtils.getLastUsedUrl(getActivity())); + } + + @SmallTest + @CommandLineFlags.Add(ChromeSwitches.ENABLE_OFFLINE_PAGES) + public void testOpenBookmarkManagerInOfflinePageNoPersist() throws InterruptedException { + EnhancedBookmarkUtils.setLastUsedUrl(getActivity(), UrlConstants.BOOKMARKS_URL); + String url = "chrome-native://bookmarks/filter/OFFLINE_PAGES?persist=0"; + openBookmarkManager(url); + EnhancedBookmarkDelegate delegate = mItemsContainer.getDelegateForTesting(); + assertEquals(EnhancedBookmarkUIState.STATE_FILTER, delegate.getCurrentState()); + assertEquals(UrlConstants.BOOKMARKS_URL, + EnhancedBookmarkUtils.getLastUsedUrl(getActivity())); + } }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 7d740cd..76a6618c 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1056,9 +1056,6 @@ <message name="IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL" desc="Label for the Repeat button of audio player"> Repeat </message> - <message name="IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL" desc="Label for a button which is used to open volume slider in audio player."> - Open volume slider - </message> <message name="IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL" desc="Label for a button which is used to open play list in audio player."> Open play list </message>
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index a6036e8..fe64b1d 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc
@@ -4,6 +4,7 @@ #include <windows.h> // NOLINT #include <shlwapi.h> // NOLINT +#include <userenv.h> // NOLINT #include "chrome/app/main_dll_loader_win.h" @@ -42,6 +43,7 @@ #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/module_util_win.h" #include "chrome/installer/util/util_constants.h" +#include "components/crash/content/app/crash_keys_win.h" #include "components/crash/content/app/crash_reporter_client.h" #include "components/crash/content/app/crashpad.h" #include "components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h" @@ -100,6 +102,39 @@ typedef int (*InitMetro)(); +#if defined(KASKO) + +// Returns a string containing a list of all modifiers for the loaded profile. +std::wstring GetProfileType() { + std::wstring profile_type; + DWORD profile_bits = 0; + if (::GetProfileType(&profile_bits)) { + static const struct { + DWORD bit; + const wchar_t* name; + } kBitNames[] = { + { PT_MANDATORY, L"mandatory" }, + { PT_ROAMING, L"roaming" }, + { PT_TEMPORARY, L"temporary" }, + }; + for (size_t i = 0; i < arraysize(kBitNames); ++i) { + const DWORD this_bit = kBitNames[i].bit; + if ((profile_bits & this_bit) != 0) { + profile_type.append(kBitNames[i].name); + profile_bits &= ~this_bit; + if (profile_bits != 0) + profile_type.append(L", "); + } + } + } else { + DWORD last_error = ::GetLastError(); + base::SStringPrintf(&profile_type, L"error %u", last_error); + } + return profile_type; +} + +#endif // KASKO + } // namespace //============================================================================= @@ -288,13 +323,24 @@ switches::kFullMemoryCrashReport)) { minidump_type = kasko::api::FULL_DUMP_TYPE; } else { - bool is_per_user_install = - g_chrome_crash_client.Get().GetIsPerUserInstall( - base::FilePath(exe_path)); - if (g_chrome_crash_client.Get().GetShouldDumpLargerDumps( + // TODO(scottmg): Point this at the common global one when it's + // moved back into the .exe. http://crbug.com/546288. + ChromeCrashReporterClient chrome_crash_client; + bool is_per_user_install = chrome_crash_client.GetIsPerUserInstall( + base::FilePath(exe_path)); + if (chrome_crash_client.GetShouldDumpLargerDumps( is_per_user_install)) { minidump_type = kasko::api::LARGER_DUMP_TYPE; } + + // TODO(scottmg): http://crbug.com/564329 Breakpad is no longer + // initialized. For now, initialize the CustomInfoEntries here so + // Kasko can pull them out. + static breakpad::CrashKeysWin crash_keys_win; + crash_keys_win.GetCustomInfo( + exe_path.value(), base::UTF8ToUTF16(process_type), + GetProfileType(), base::CommandLine::ForCurrentProcess(), + &chrome_crash_client); } kasko_client_.reset(
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index a6461122..261f3f4 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -300,7 +300,6 @@ <structure type="chrome_scaled_image" name="IDR_FIND_DIALOG_RIGHT" file="common/find_dialog_right.png" /> <structure type="chrome_scaled_image" name="IDR_FIND_DLG_LEFT_BACKGROUND" file="common/find_dlg_left_bg.png" /> <structure type="chrome_scaled_image" name="IDR_FIND_DLG_RIGHT_BACKGROUND" file="common/find_dlg_right_bg.png" /> - <structure type="chrome_scaled_image" name="IDR_FLAGS_FAVICON" file="common/favicon_flags.png" /> <if expr="toolkit_views or is_macosx or is_ios"> <structure type="chrome_scaled_image" name="IDR_FORWARD" file="common/browser_forward_normal.png" /> <structure type="chrome_scaled_image" name="IDR_FORWARD_D" file="common/browser_forward_disabled.png" /> @@ -581,14 +580,18 @@ </if> <if expr="not _google_chrome"> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="chromium/product_logo_16.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_26" file="chromium/product_logo_26.png" /> + <if expr="is_macosx"> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_26" file="chromium/product_logo_26.png" /> + </if> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32" file="chromium/product_logo_32.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_NAME_48" file="chromium/product_logo_name_48.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="chromium/product_logo_white.png" /> </if> <if expr="_google_chrome"> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="google_chrome/product_logo_16.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_26" file="google_chrome/product_logo_26.png" /> + <if expr="is_macosx"> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_26" file="google_chrome/product_logo_26.png" /> + </if> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32" file="google_chrome/product_logo_32.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/product_logo_32_beta.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_CANARY" file="google_chrome/product_logo_32_canary.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 41f867fc..df1c6952 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -584,8 +584,11 @@ sources += [ "ui/views/frame/browser_frame_mus.cc", "ui/views/frame/browser_frame_mus.h", + "ui/views/frame/browser_non_client_frame_view_mus.cc", + "ui/views/frame/browser_non_client_frame_view_mus.h", ] deps += [ + "//components/mus/public/cpp", "//content/public/common", "//mojo/runner/child:lib", "//ui/aura",
diff --git a/chrome/browser/android/data_usage/data_use_tab_helper.cc b/chrome/browser/android/data_usage/data_use_tab_helper.cc index 5f9b870..e0a2045 100644 --- a/chrome/browser/android/data_usage/data_use_tab_helper.cc +++ b/chrome/browser/android/data_usage/data_use_tab_helper.cc
@@ -32,6 +32,11 @@ if (!navigation_handle->IsInMainFrame()) return; + // crbug.com/564871: Calling GetPageTransition() may fail if the navigation + // has not committed. + if (!navigation_handle->HasCommitted()) + return; + // Notify the DataUseUITabModel. chrome::android::DataUseUITabModel* data_use_ui_tab_model = chrome::android::DataUseUITabModelFactory::GetForBrowserContext(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index 464e2f5e..fae9849f 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -8,6 +8,7 @@ #include "base/location.h" #include "base/strings/string16.h" #include "base/task/cancelable_task_tracker.h" +#include "chrome/browser/android/offline_pages/offline_page_model_factory.h" #include "chrome/browser/android/shortcut_helper.h" #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/manifest/manifest_icon_downloader.h" @@ -18,6 +19,9 @@ #include "chrome/common/web_application_info.h" #include "components/dom_distiller/core/url_utils.h" #include "components/favicon/core/favicon_service.h" +#include "components/offline_pages/offline_page_feature.h" +#include "components/offline_pages/offline_page_item.h" +#include "components/offline_pages/offline_page_model.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" @@ -45,8 +49,7 @@ is_icon_saved_(false), is_ready_(false), icon_timeout_timer_(false, false), - shortcut_info_(dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl( - web_contents->GetURL())), + shortcut_info_(GetShortcutUrl(web_contents->GetURL())), ideal_icon_size_in_dp_(ideal_icon_size_in_dp), minimum_icon_size_in_dp_(minimum_icon_size_in_dp), ideal_splash_image_size_in_dp_(ideal_splash_image_size_in_dp), @@ -271,3 +274,23 @@ is_ready_ = true; weak_observer_->OnDataAvailable(shortcut_info_, shortcut_icon_); } + +GURL AddToHomescreenDataFetcher::GetShortcutUrl(const GURL& actual_url) { + GURL shortcut_url = + dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(actual_url); + + if (!offline_pages::IsOfflinePagesEnabled()) + return shortcut_url; + + Profile* profile = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()); + + offline_pages::OfflinePageModel* offline_page_model = + offline_pages::OfflinePageModelFactory::GetForBrowserContext(profile); + const offline_pages::OfflinePageItem* offline_page = + offline_page_model->GetPageByOfflineURL(shortcut_url); + if (!offline_page) + return shortcut_url; + + return offline_page->url; +}
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h index 173b45f..58a3af6 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -100,6 +100,11 @@ // Notifies the observer that the shortcut data is all available. void NotifyObserver(const SkBitmap& icon, bool is_generated); + // Looks up the original, online URL of the site requested. The URL from the + // WebContents may be an offline page or a distilled article which is not + // appropriate for a home screen shortcut. + GURL GetShortcutUrl(const GURL& original_url); + Observer* weak_observer_; bool is_waiting_for_web_application_info_;
diff --git a/chrome/browser/chromeos/extensions/external_cache_unittest.cc b/chrome/browser/chromeos/extensions/external_cache_unittest.cc index 58f5268f..c0e036c5 100644 --- a/chrome/browser/chromeos/extensions/external_cache_unittest.cc +++ b/chrome/browser/chromeos/extensions/external_cache_unittest.cc
@@ -70,11 +70,6 @@ pool_owner_->pool()->GetNamedSequenceToken("background")); } - void TearDown() override { - pool_owner_->pool()->Shutdown(); - base::RunLoop().RunUntilIdle(); - } - // ExternalCache::Delegate: void OnExtensionListsUpdated(const base::DictionaryValue* prefs) override { prefs_.reset(prefs->DeepCopy());
diff --git a/chrome/browser/chromeos/extensions/file_manager/OWNERS b/chrome/browser/chromeos/extensions/file_manager/OWNERS index 7ab4392..5f9e355 100644 --- a/chrome/browser/chromeos/extensions/file_manager/OWNERS +++ b/chrome/browser/chromeos/extensions/file_manager/OWNERS
@@ -1,4 +1,5 @@ # This should match chrome/browser/chromeos/file_manager/OWNERS +fukino@chromium.org hirono@chromium.org kinaba@chromium.org mtomasz@chromium.org
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index 87684e5e..5f78e2cf 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -254,8 +254,6 @@ IDS_AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL); SET_STRING("AUDIO_PLAYER_REPEAT_BUTTON_LABEL", IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL); - SET_STRING("AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL", - IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL); SET_STRING("AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL", IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL); }
diff --git a/chrome/browser/chromeos/file_manager/OWNERS b/chrome/browser/chromeos/file_manager/OWNERS index 12062530c..82f9484 100644 --- a/chrome/browser/chromeos/file_manager/OWNERS +++ b/chrome/browser/chromeos/file_manager/OWNERS
@@ -1,7 +1,5 @@ +fukino@chromium.org hirono@chromium.org kinaba@chromium.org mtomasz@chromium.org yoshiki@chromium.org - -per-file file_manager_browsertest.cc=fukino@chromium.org -per-file *_jstest.cc=fukino@chromium.org
diff --git a/chrome/browser/chromeos/power/cpu_data_collector.cc b/chrome/browser/chromeos/power/cpu_data_collector.cc index f09cb95..3166c60 100644 --- a/chrome/browser/chromeos/power/cpu_data_collector.cc +++ b/chrome/browser/chromeos/power/cpu_data_collector.cc
@@ -45,9 +45,14 @@ // Format of the suffix of the path to the file which contains freq state // information of a CPU. -const char kCpuFreqTimeInStatePathSuffixFormat[] = +const char kCpuFreqTimeInStatePathSuffixOldFormat[] = "/cpu%d/cpufreq/stats/time_in_state"; +// The path to the file which contains cpu freq state informatino of a CPU +// in newer kernel. +const char kCpuFreqTimeInStateNewPath[] = + "/sys/devices/system/cpu/cpufreq/all_time_in_state"; + // Format of the suffix of the path to the directory which contains information // about an idle state of a CPU on the system. const char kCpuIdleStateDirPathSuffixFormat[] = "/cpu%d/cpuidle/state%d"; @@ -62,8 +67,7 @@ // Returns the index at which |str| is in |vector|. If |str| is not present in // |vector|, then it is added to it before its index is returned. -size_t IndexInVector(const std::string& str, - std::vector<std::string>* vector) { +size_t IndexInVector(const std::string& str, std::vector<std::string>* vector) { for (size_t i = 0; i < vector->size(); ++i) { if (str == (*vector)[i]) return i; @@ -188,6 +192,51 @@ } } +bool ReadCpuFreqFromOldFile( + const std::string& path, + std::vector<std::string>* cpu_freq_state_names, + CpuDataCollector::StateOccupancySample* freq_sample) { + std::string time_in_state_string; + // Note time as close to reading the file as possible. This is + // not possible for idle state samples as the information for + // each state there is recorded in different files. + if (!base::ReadFileToString(base::FilePath(path), &time_in_state_string)) { + LOG(ERROR) << "Error reading " << path << ". " + << "Dropping sample."; + return false; + } + + std::vector<base::StringPiece> lines = base::SplitStringPiece( + time_in_state_string, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + // The last line could end with '\n'. Ignore the last empty string in + // such cases. + size_t state_count = lines.size(); + if (state_count > 0 && lines.back().empty()) + state_count -= 1; + for (size_t state = 0; state < state_count; ++state) { + int freq_in_khz; + int64 occupancy_time_centisecond; + + // Occupancy of each state is in the format "<state> <time>" + std::vector<base::StringPiece> pair = base::SplitStringPiece( + lines[state], " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + if (pair.size() == 2 && base::StringToInt(pair[0], &freq_in_khz) && + base::StringToInt64(pair[1], &occupancy_time_centisecond)) { + const std::string state_name = base::IntToString(freq_in_khz / 1000); + size_t index = IndexInVector(state_name, cpu_freq_state_names); + if (index >= freq_sample->time_in_state.size()) + freq_sample->time_in_state.resize(index + 1); + // The occupancy time is in units of centiseconds. + freq_sample->time_in_state[index] = occupancy_time_centisecond * 10; + } else { + LOG(ERROR) << "Bad format in " << path << ". " + << "Dropping sample."; + return false; + } + } + return true; +} + // Samples the CPU freq state information from sysfs. |cpu_count| is the number // of possible CPUs on the system. Sample at index i in |freq_samples| // corresponds to the freq state information of the i-th CPU. @@ -200,17 +249,27 @@ CpuDataCollector::StateOccupancySample freq_sample; freq_sample.time_in_state.reserve(cpu_freq_state_names->size()); + freq_sample.time = base::Time::Now(); if (!CpuIsOnline(cpu)) { - freq_sample.time = base::Time::Now(); freq_sample.cpu_online = false; } else { freq_sample.cpu_online = true; - const std::string time_in_state_path_format = base::StringPrintf( - "%s%s", kCpuDataPathBase, kCpuFreqTimeInStatePathSuffixFormat); - const std::string time_in_state_path = base::StringPrintf( - time_in_state_path_format.c_str(), cpu); - if (!base::PathExists(base::FilePath(time_in_state_path))) { + const std::string time_in_state_path_old_format = base::StringPrintf( + "%s%s", kCpuDataPathBase, kCpuFreqTimeInStatePathSuffixOldFormat); + const std::string time_in_state_path = + base::StringPrintf(time_in_state_path_old_format.c_str(), cpu); + if (base::PathExists(base::FilePath(time_in_state_path))) { + if (!ReadCpuFreqFromOldFile(time_in_state_path, cpu_freq_state_names, + &freq_sample)) { + freq_samples->clear(); + return; + } + } else if (base::PathExists(base::FilePath(kCpuFreqTimeInStateNewPath))) { + // TODO(oshima): Parse the new file. crbug.com/548510. + freq_samples->clear(); + return; + } else { // If the path to the 'time_in_state' for a single CPU is missing, // then 'time_in_state' for all CPUs is missing. This could happen // on a VM where the 'cpufreq_stats' kernel module is not loaded. @@ -219,53 +278,6 @@ freq_samples->clear(); return; } - - std::string time_in_state_string; - // Note time as close to reading the file as possible. This is not - // possible for idle state samples as the information for each state there - // is recorded in different files. - base::Time now = base::Time::Now(); - if (!base::ReadFileToString(base::FilePath(time_in_state_path), - &time_in_state_string)) { - LOG(ERROR) << "Error reading " << time_in_state_path << ". " - << "Dropping sample."; - freq_samples->clear(); - return; - } - - freq_sample.time = now; - - std::vector<base::StringPiece> lines = - base::SplitStringPiece(time_in_state_string, "\n", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - // The last line could end with '\n'. Ignore the last empty string in - // such cases. - size_t state_count = lines.size(); - if (state_count > 0 && lines.back().empty()) - state_count -= 1; - for (size_t state = 0; state < state_count; ++state) { - int freq_in_khz; - int64 occupancy_time_centisecond; - - // Occupancy of each state is in the format "<state> <time>" - std::vector<base::StringPiece> pair = base::SplitStringPiece( - lines[state], " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (pair.size() == 2 && - base::StringToInt(pair[0], &freq_in_khz) && - base::StringToInt64(pair[1], &occupancy_time_centisecond)) { - const std::string state_name = base::IntToString(freq_in_khz / 1000); - size_t index = IndexInVector(state_name, cpu_freq_state_names); - if (index >= freq_sample.time_in_state.size()) - freq_sample.time_in_state.resize(index + 1); - // The occupancy time is in units of centiseconds. - freq_sample.time_in_state[index] = occupancy_time_centisecond * 10; - } else { - LOG(ERROR) << "Bad format in " << time_in_state_path << ". " - << "Dropping sample."; - freq_samples->clear(); - return; - } - } } freq_samples->push_back(freq_sample);
diff --git a/chrome/browser/devtools/devtools_network_controller.cc b/chrome/browser/devtools/devtools_network_controller.cc index 03ba6e27..d9021e29 100644 --- a/chrome/browser/devtools/devtools_network_controller.cc +++ b/chrome/browser/devtools/devtools_network_controller.cc
@@ -9,25 +9,23 @@ #include "net/http/http_request_info.h" DevToolsNetworkController::DevToolsNetworkController() - : default_interceptor_(new DevToolsNetworkInterceptor()), - appcache_interceptor_(new DevToolsNetworkInterceptor()) {} + : appcache_interceptor_(new DevToolsNetworkInterceptor()) {} DevToolsNetworkController::~DevToolsNetworkController() { DCHECK(thread_checker_.CalledOnValidThread()); } -base::WeakPtr<DevToolsNetworkInterceptor> -DevToolsNetworkController::GetInterceptor( +DevToolsNetworkInterceptor* DevToolsNetworkController::GetInterceptor( const std::string& client_id) { DCHECK(thread_checker_.CalledOnValidThread()); if (!interceptors_.size() || client_id.empty()) - return default_interceptor_->GetWeakPtr(); + return nullptr; DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id); if (!interceptor) - return default_interceptor_->GetWeakPtr(); + return nullptr; - return interceptor->GetWeakPtr(); + return interceptor; } void DevToolsNetworkController::SetNetworkState( @@ -58,13 +56,13 @@ bool has_offline_interceptors = false; InterceptorMap::iterator it = interceptors_.begin(); for (; it != interceptors_.end(); ++it) { - if (it->second->conditions()->offline()) { + if (it->second->IsOffline()) { has_offline_interceptors = true; break; } } - bool is_appcache_offline = appcache_interceptor_->conditions()->offline(); + bool is_appcache_offline = appcache_interceptor_->IsOffline(); if (is_appcache_offline != has_offline_interceptors) { scoped_ptr<DevToolsNetworkConditions> appcache_conditions( new DevToolsNetworkConditions(has_offline_interceptors));
diff --git a/chrome/browser/devtools/devtools_network_controller.h b/chrome/browser/devtools/devtools_network_controller.h index 789003f..89fa2fb1 100644 --- a/chrome/browser/devtools/devtools_network_controller.h +++ b/chrome/browser/devtools/devtools_network_controller.h
@@ -10,7 +10,6 @@ #include "base/containers/scoped_ptr_hash_map.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" class DevToolsNetworkConditions; @@ -28,7 +27,7 @@ const std::string& client_id, scoped_ptr<DevToolsNetworkConditions> conditions); - base::WeakPtr<DevToolsNetworkInterceptor> GetInterceptor( + DevToolsNetworkInterceptor* GetInterceptor( const std::string& client_id); private: @@ -36,7 +35,6 @@ base::ScopedPtrHashMap<std::string, scoped_ptr<DevToolsNetworkInterceptor>>; - scoped_ptr<DevToolsNetworkInterceptor> default_interceptor_; scoped_ptr<DevToolsNetworkInterceptor> appcache_interceptor_; InterceptorMap interceptors_; base::ThreadChecker thread_checker_;
diff --git a/chrome/browser/devtools/devtools_network_controller_unittest.cc b/chrome/browser/devtools/devtools_network_controller_unittest.cc index b399bb1a..1c57198 100644 --- a/chrome/browser/devtools/devtools_network_controller_unittest.cc +++ b/chrome/browser/devtools/devtools_network_controller_unittest.cc
@@ -85,11 +85,11 @@ bool ShouldFail() { if (transaction_->interceptor_) - return transaction_->interceptor_->ShouldFail(); - base::WeakPtr<DevToolsNetworkInterceptor> interceptor = + return transaction_->interceptor_->IsOffline(); + DevToolsNetworkInterceptor* interceptor = controller_.GetInterceptor(kClientId); EXPECT_TRUE(!!interceptor); - return interceptor->ShouldFail(); + return interceptor->IsOffline(); } bool HasStarted() { @@ -100,12 +100,15 @@ return transaction_->failed_; } + void CancelTransaction() { + transaction_.reset(); + } + ~DevToolsNetworkControllerHelper() { RemoveMockTransaction(&mock_transaction_); } TestCallback* callback() { return &callback_; } - MockTransaction* mock_transaction() { return &mock_transaction_; } DevToolsNetworkController* controller() { return &controller_; } DevToolsNetworkTransaction* transaction() { return transaction_.get(); } @@ -176,16 +179,15 @@ EXPECT_EQ(callback->run_count(), 0); helper.SetNetworkState(kClientId, true); + EXPECT_EQ(callback->run_count(), 0); + + // Wait until HttpTrancation completes reading and invokes callback. + // DevToolsNetworkTransaction should report error instead. + base::RunLoop().RunUntilIdle(); EXPECT_EQ(callback->run_count(), 1); EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED); - // Wait until HttpTrancation completes reading and invokes callback. - // DevToolsNetworkTransaction should ignore callback, because it has - // reported network error already. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(callback->run_count(), 1); - - // Check that transaction in not failed second time. + // Check that transaction is not failed second time. helper.SetNetworkState(kClientId, false); helper.SetNetworkState(kClientId, true); EXPECT_EQ(callback->run_count(), 1); @@ -200,10 +202,12 @@ EXPECT_TRUE(helper.HasStarted()); helper.SetNetworkState(kClientId, true); - EXPECT_TRUE(helper.HasFailed()); + // Not failed yet, as no IO was initiated. + EXPECT_FALSE(helper.HasFailed()); scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64)); rv = helper.Read(); + // Fails on first IO. EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED); // Check that callback is never invoked. @@ -211,4 +215,34 @@ EXPECT_EQ(helper.callback()->run_count(), 0); } +TEST(DevToolsNetworkControllerTest, CancelTransaction) { + DevToolsNetworkControllerHelper helper; + helper.SetNetworkState(kClientId, false); + + int rv = helper.Start(); + EXPECT_EQ(rv, net::OK); + EXPECT_TRUE(helper.HasStarted()); + helper.CancelTransaction(); + + // Should not crash. + helper.SetNetworkState(kClientId, true); + helper.SetNetworkState(kClientId, false); + base::RunLoop().RunUntilIdle(); +} + +TEST(DevToolsNetworkControllerTest, CancelFailedTransaction) { + DevToolsNetworkControllerHelper helper; + helper.SetNetworkState(kClientId, true); + + int rv = helper.Start(); + EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED); + EXPECT_TRUE(helper.HasStarted()); + helper.CancelTransaction(); + + // Should not crash. + helper.SetNetworkState(kClientId, true); + helper.SetNetworkState(kClientId, false); + base::RunLoop().RunUntilIdle(); +} + } // namespace test
diff --git a/chrome/browser/devtools/devtools_network_interceptor.cc b/chrome/browser/devtools/devtools_network_interceptor.cc index 005ebd4b..47c2e25 100644 --- a/chrome/browser/devtools/devtools_network_interceptor.cc +++ b/chrome/browser/devtools/devtools_network_interceptor.cc
@@ -9,6 +9,7 @@ #include "base/time/time.h" #include "chrome/browser/devtools/devtools_network_conditions.h" +#include "net/base/net_errors.h" namespace { @@ -16,6 +17,12 @@ } // namespace +DevToolsNetworkInterceptor::ThrottleRecord::ThrottleRecord() { +} + +DevToolsNetworkInterceptor::ThrottleRecord::~ThrottleRecord() { +} + DevToolsNetworkInterceptor::DevToolsNetworkInterceptor() : conditions_(new DevToolsNetworkConditions()), weak_ptr_factory_(this) { @@ -29,37 +36,6 @@ return weak_ptr_factory_.GetWeakPtr(); } -void DevToolsNetworkInterceptor::AddThrottable( - Throttable* throttable) { - DCHECK(throttables_.find(throttable) == throttables_.end()); - throttables_.insert(throttable); -} - -void DevToolsNetworkInterceptor::RemoveThrottable( - Throttable* throttable) { - DCHECK(throttables_.find(throttable) != throttables_.end()); - throttables_.erase(throttable); - - if (!conditions_->IsThrottling()) - return; - - base::TimeTicks now = base::TimeTicks::Now(); - UpdateThrottled(now); - throttled_.erase( - std::remove(throttled_.begin(), throttled_.end(), throttable), - throttled_.end()); - - Suspended::iterator it = suspended_.begin(); - for (; it != suspended_.end(); ++it) { - if (it->first == throttable) { - suspended_.erase(it); - break; - } - } - - ArmTimer(now); -} - void DevToolsNetworkInterceptor::UpdateConditions( scoped_ptr<DevToolsNetworkConditions> conditions) { DCHECK(conditions); @@ -69,56 +45,43 @@ conditions_ = conditions.Pass(); - if (conditions_->offline()) { + bool offline = conditions_->offline(); + if (offline || !conditions_->IsThrottling()) { timer_.Stop(); - throttled_.clear(); - suspended_.clear(); - Throttables old_throttables(throttables_); - Throttables::iterator it = old_throttables.begin(); - for (;it != old_throttables.end(); ++it) { - if (throttables_.find(*it) == throttables_.end()) - continue; - (*it)->Fail(); + ThrottleRecords throttled; + throttled.swap(throttled_); + for (const ThrottleRecord& record : throttled) { + record.callback.Run( + offline ? net::ERR_INTERNET_DISCONNECTED : record.result, + record.bytes); } + + ThrottleRecords suspended; + suspended.swap(suspended_); + for (const ThrottleRecord& record : suspended) { + record.callback.Run( + offline ? net::ERR_INTERNET_DISCONNECTED : record.result, + record.bytes); + } + return; } - if (conditions_->IsThrottling()) { - DCHECK(conditions_->download_throughput() != 0); - offset_ = now; - last_tick_ = 0; - int64_t us_tick_length = - (1000000L * kPacketSize) / conditions_->download_throughput(); - DCHECK(us_tick_length != 0); - if (us_tick_length == 0) - us_tick_length = 1; - tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length); - latency_length_ = base::TimeDelta(); - double latency = conditions_->latency(); - if (latency > 0) - latency_length_ = base::TimeDelta::FromMillisecondsD(latency); - ArmTimer(now); - } else { - timer_.Stop(); - - std::vector<Throttable*> throttled; - throttled.swap(throttled_); - size_t throttle_count = throttled.size(); - for (size_t i = 0; i < throttle_count; ++i) - FireThrottledCallback(throttled[i]); - - Suspended suspended; - suspended.swap(suspended_); - size_t suspend_count = suspended.size(); - for (size_t i = 0; i < suspend_count; ++i) - FireThrottledCallback(suspended[i].first); - } -} - -void DevToolsNetworkInterceptor::FireThrottledCallback( - Throttable* throttable) { - if (throttables_.find(throttable) != throttables_.end()) - throttable->ThrottleFinished(); + // Throttling. + DCHECK(conditions_->download_throughput() != 0); + offset_ = now; + last_tick_ = 0; + int64_t us_tick_length = + (1000000L * kPacketSize) / conditions_->download_throughput(); + DCHECK(us_tick_length != 0); + if (us_tick_length == 0) + us_tick_length = 1; + tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length); + latency_length_ = base::TimeDelta(); + double latency = conditions_->latency(); + if (latency > 0) + latency_length_ = base::TimeDelta::FromMillisecondsD(latency); + ArmTimer(now); } void DevToolsNetworkInterceptor::UpdateThrottled( @@ -135,8 +98,8 @@ int64_t shift = ticks % length; for (int64_t i = 0; i < length; ++i) { - throttled_[i]->Throttled( - (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0)); + throttled_[i].bytes -= + (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0); } std::rotate(throttled_.begin(), throttled_.begin() + shift, throttled_.end()); @@ -148,13 +111,12 @@ base::TimeTicks now) { int64_t activation_baseline = (now - latency_length_ - base::TimeTicks()).InMicroseconds(); - Suspended suspended; - Suspended::iterator it = suspended_.begin(); - for (; it != suspended_.end(); ++it) { - if (it->second <= activation_baseline) - throttled_.push_back(it->first); + ThrottleRecords suspended; + for (const ThrottleRecord& record : suspended_) { + if (record.send_end <= activation_baseline) + throttled_.push_back(record); else - suspended.push_back(*it); + suspended.push_back(record); } suspended_.swap(suspended); } @@ -163,20 +125,18 @@ base::TimeTicks now = base::TimeTicks::Now(); UpdateThrottled(now); - std::vector<Throttable*> active; - std::vector<Throttable*> finished; - size_t length = throttled_.size(); - for (size_t i = 0; i < length; ++i) { - if (throttled_[i]->ThrottledByteCount() < 0) - finished.push_back(throttled_[i]); + ThrottleRecords active; + ThrottleRecords finished; + for (const ThrottleRecord& record : throttled_) { + if (record.bytes < 0) + finished.push_back(record); else - active.push_back(throttled_[i]); + active.push_back(record); } throttled_.swap(active); - length = finished.size(); - for (size_t i = 0; i < length; ++i) - FireThrottledCallback(finished[i]); + for (const ThrottleRecord& record : finished) + record.callback.Run(record.result, record.bytes); ArmTimer(now); } @@ -188,7 +148,7 @@ return; int64_t min_ticks_left = 0x10000L; for (size_t i = 0; i < throttle_count; ++i) { - int64_t packets_left = (throttled_[i]->ThrottledByteCount() + + int64_t packets_left = (throttled_[i].bytes + kPacketSize - 1) / kPacketSize; int64_t ticks_left = (i + 1) + throttle_count * (packets_left - 1); if (i == 0 || ticks_left < min_ticks_left) @@ -199,8 +159,8 @@ int64_t min_baseline = std::numeric_limits<int64>::max(); for (size_t i = 0; i < suspend_count; ++i) { - if (suspended_[i].second < min_baseline) - min_baseline = suspended_[i].second; + if (suspended_[i].send_end < min_baseline) + min_baseline = suspended_[i].send_end; } if (suspend_count) { base::TimeTicks activation_time = base::TimeTicks() + @@ -217,28 +177,56 @@ base::Unretained(this))); } -void DevToolsNetworkInterceptor::Throttle( - Throttable* throttable, bool start) { +int DevToolsNetworkInterceptor::StartThrottle( + int result, + int64_t bytes, + base::TimeTicks send_end, + bool start, + const ThrottleCallback& callback) { + if (result < 0) + return result; + + if (conditions_->offline()) + return net::ERR_INTERNET_DISCONNECTED; + + if (!conditions_->IsThrottling()) + return result; + + ThrottleRecord record; + record.result = result; + record.bytes = bytes; + record.callback = callback; + base::TimeTicks now = base::TimeTicks::Now(); UpdateThrottled(now); if (start && latency_length_ != base::TimeDelta()) { - base::TimeTicks send_end; - throttable->GetSendEndTiming(&send_end); - if (send_end.is_null()) - send_end = now; - int64_t us_send_end = (send_end - base::TimeTicks()).InMicroseconds(); - suspended_.push_back(std::make_pair(throttable, us_send_end)); + record.send_end = (send_end - base::TimeTicks()).InMicroseconds(); + suspended_.push_back(record); UpdateSuspended(now); } else { - throttled_.push_back(throttable); + throttled_.push_back(record); } ArmTimer(now); + + return net::ERR_IO_PENDING; } -bool DevToolsNetworkInterceptor::ShouldFail() { +void DevToolsNetworkInterceptor::StopThrottle( + const ThrottleCallback& callback) { + RemoveRecord(&throttled_, callback); + RemoveRecord(&suspended_, callback); +} + +void DevToolsNetworkInterceptor::RemoveRecord( + ThrottleRecords* records, const ThrottleCallback& callback) { + records->erase( + std::remove_if(records->begin(), records->end(), + [&callback](const ThrottleRecord& record){ + return record.callback.Equals(callback); + }), + records->end()); +} + +bool DevToolsNetworkInterceptor::IsOffline() { return conditions_->offline(); } - -bool DevToolsNetworkInterceptor::ShouldThrottle() { - return conditions_->IsThrottling(); -}
diff --git a/chrome/browser/devtools/devtools_network_interceptor.h b/chrome/browser/devtools/devtools_network_interceptor.h index 18e9409..2deb8804 100644 --- a/chrome/browser/devtools/devtools_network_interceptor.h +++ b/chrome/browser/devtools/devtools_network_interceptor.h
@@ -25,15 +25,7 @@ // specific client id. class DevToolsNetworkInterceptor { public: - class Throttable { - public: - virtual ~Throttable() {} - virtual void Fail() = 0; - virtual int64_t ThrottledByteCount() = 0; - virtual void Throttled(int64_t count) = 0; - virtual void ThrottleFinished() = 0; - virtual void GetSendEndTiming(base::TimeTicks* send_end) = 0; - }; + using ThrottleCallback = base::Callback<void(int, int64_t)>; DevToolsNetworkInterceptor(); virtual ~DevToolsNetworkInterceptor(); @@ -43,16 +35,14 @@ // Applies network emulation configuration. void UpdateConditions(scoped_ptr<DevToolsNetworkConditions> conditions); - void AddThrottable(Throttable* throttable); - void RemoveThrottable(Throttable* throttable); + int StartThrottle(int result, + int64_t bytes, + base::TimeTicks send_end, + bool start, + const ThrottleCallback& callback); + void StopThrottle(const ThrottleCallback& callback); - bool ShouldFail(); - bool ShouldThrottle(); - void Throttle(Throttable* throttable, bool start); - - const DevToolsNetworkConditions* conditions() const { - return conditions_.get(); - } + bool IsOffline(); private: scoped_ptr<DevToolsNetworkConditions> conditions_; @@ -62,17 +52,24 @@ void ArmTimer(base::TimeTicks now); void OnTimer(); - void FireThrottledCallback(Throttable* throttable); + struct ThrottleRecord { + public: + ThrottleRecord(); + ~ThrottleRecord(); + int result; + int64_t bytes; + int64_t send_end; + ThrottleCallback callback; + }; + using ThrottleRecords = std::vector<ThrottleRecord>; - typedef std::set<Throttable*> Throttables; - Throttables throttables_; + void RemoveRecord(ThrottleRecords* records, const ThrottleCallback& callback); // Throttables suspended for a "latency" period. - typedef std::vector<std::pair<Throttable*, int64_t>> Suspended; - Suspended suspended_; + ThrottleRecords suspended_; // Throttable waiting certain amount of transfer to be "accounted". - std::vector<Throttable*> throttled_; + ThrottleRecords throttled_; base::OneShotTimer timer_; base::TimeTicks offset_;
diff --git a/chrome/browser/devtools/devtools_network_transaction.cc b/chrome/browser/devtools/devtools_network_transaction.cc index 5f815aa..a2e6b78f 100644 --- a/chrome/browser/devtools/devtools_network_transaction.cc +++ b/chrome/browser/devtools/devtools_network_transaction.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/devtools/devtools_network_transaction.h" +#include "base/callback_helpers.h" #include "chrome/browser/devtools/devtools_network_controller.h" #include "chrome/browser/devtools/devtools_network_interceptor.h" #include "net/base/load_timing_info.h" @@ -22,95 +23,64 @@ DevToolsNetworkTransaction::DevToolsNetworkTransaction( DevToolsNetworkController* controller, scoped_ptr<net::HttpTransaction> network_transaction) - : controller_(controller), + : throttled_byte_count_(0), + controller_(controller), network_transaction_(network_transaction.Pass()), - request_(NULL), - failed_(false), - throttled_byte_count_(0), - callback_type_(NONE), - proxy_callback_(base::Bind(&DevToolsNetworkTransaction::OnCallback, - base::Unretained(this))) { + request_(nullptr), + failed_(false) { DCHECK(controller); } DevToolsNetworkTransaction::~DevToolsNetworkTransaction() { - if (interceptor_) - interceptor_->RemoveThrottable(this); + if (interceptor_ && !throttle_callback_.is_null()) + interceptor_->StopThrottle(throttle_callback_); } -int64_t DevToolsNetworkTransaction::ThrottledByteCount() { - return throttled_byte_count_; +void DevToolsNetworkTransaction::IOCallback( + const net::CompletionCallback& callback, bool start, int result) { + result = Throttle(callback, start, result); + if (result != net::ERR_IO_PENDING) + callback.Run(result); } -void DevToolsNetworkTransaction::Throttled(int64_t count) { - throttled_byte_count_ -= count; -} +int DevToolsNetworkTransaction::Throttle( + const net::CompletionCallback& callback, bool start, int result) { + if (failed_) + return net::ERR_INTERNET_DISCONNECTED; + if (!interceptor_ || result < 0) + return result; -void DevToolsNetworkTransaction::GetSendEndTiming(base::TimeTicks* send_end) { - net::LoadTimingInfo load_timing_info; - if (GetLoadTimingInfo(&load_timing_info)) - *send_end = load_timing_info.send_end; -} - -void DevToolsNetworkTransaction::Throttle(int result) { - throttled_result_ = result; - - if (callback_type_ == START) + base::TimeTicks send_end; + if (start) { throttled_byte_count_ += network_transaction_->GetTotalReceivedBytes(); + net::LoadTimingInfo load_timing_info; + if (GetLoadTimingInfo(&load_timing_info)) + send_end = load_timing_info.send_end; + if (send_end.is_null()) + send_end = base::TimeTicks::Now(); + } if (result > 0) throttled_byte_count_ += result; - if (interceptor_) - interceptor_->Throttle(this, callback_type_ == START); + throttle_callback_ = base::Bind(&DevToolsNetworkTransaction::ThrottleCallback, + base::Unretained(this), callback); + int rv = interceptor_->StartThrottle( + result, throttled_byte_count_, send_end, start, throttle_callback_); + if (rv != net::ERR_IO_PENDING) + throttle_callback_.Reset(); + if (rv == net::ERR_INTERNET_DISCONNECTED) + Fail(); + return rv; } -void DevToolsNetworkTransaction::OnCallback(int rv) { - if (failed_) - return; - DCHECK(!callback_.is_null()); - if (callback_type_ == START || callback_type_ == READ) { - if (interceptor_ && interceptor_->ShouldThrottle()) { - Throttle(rv); - return; - } - } - net::CompletionCallback callback = callback_; - callback_.Reset(); - callback_type_ = NONE; - callback.Run(rv); -} - -int DevToolsNetworkTransaction::SetupCallback( - net::CompletionCallback callback, - int result, - CallbackType callback_type) { - DCHECK(callback_type_ == NONE); - - if (result == net::ERR_IO_PENDING) { - callback_type_ = callback_type; - callback_ = callback; - return result; - } - - if (!interceptor_ || !interceptor_->ShouldThrottle()) - return result; - - // Only START and READ operation throttling is supported. - if (callback_type != START && callback_type != READ) - return result; - - // In case of error |throttled_byte_count_| is unknown. - if (result < 0) - return result; - - // URLRequestJob relies on synchronous end-of-stream notification. - if (callback_type == READ && result == 0) - return result; - - callback_type_ = callback_type; - callback_ = callback; - Throttle(result); - return net::ERR_IO_PENDING; +void DevToolsNetworkTransaction::ThrottleCallback( + const net::CompletionCallback& callback, int result, int64_t bytes) { + DCHECK(!throttle_callback_.is_null()); + throttle_callback_.Reset(); + if (result == net::ERR_INTERNET_DISCONNECTED) + Fail(); + throttled_byte_count_ = bytes; + callback.Run(result); } void DevToolsNetworkTransaction::Fail() { @@ -119,16 +89,18 @@ failed_ = true; network_transaction_->SetBeforeNetworkStartCallback( BeforeNetworkStartCallback()); - if (interceptor_) { - interceptor_->RemoveThrottable(this); + if (interceptor_) interceptor_.reset(); +} + +bool DevToolsNetworkTransaction::CheckFailed() { + if (failed_) + return true; + if (interceptor_ && interceptor_->IsOffline()) { + Fail(); + return true; } - if (callback_.is_null()) - return; - net::CompletionCallback callback = callback_; - callback_.Reset(); - callback_type_ = NONE; - callback.Run(net::ERR_INTERNET_DISCONNECTED); + return false; } int DevToolsNetworkTransaction::Start( @@ -139,74 +111,78 @@ request_ = request; std::string client_id; - ProcessRequest(&client_id); - interceptor_ = controller_->GetInterceptor(client_id); - - if (interceptor_ && interceptor_->ShouldFail()) { - failed_ = true; - network_transaction_->SetBeforeNetworkStartCallback( - BeforeNetworkStartCallback()); - interceptor_.reset(); - return net::ERR_INTERNET_DISCONNECTED; + bool has_devtools_client_id = request_->extra_headers.HasHeader( + kDevToolsEmulateNetworkConditionsClientId); + if (has_devtools_client_id) { + custom_request_.reset(new net::HttpRequestInfo(*request_)); + custom_request_->extra_headers.GetHeader( + kDevToolsEmulateNetworkConditionsClientId, &client_id); + custom_request_->extra_headers.RemoveHeader( + kDevToolsEmulateNetworkConditionsClientId); + request_ = custom_request_.get(); } + DevToolsNetworkInterceptor* interceptor = + controller_->GetInterceptor(client_id); + if (interceptor) + interceptor_ = interceptor->GetWeakPtr(); + + if (CheckFailed()) + return net::ERR_INTERNET_DISCONNECTED; + if (!interceptor_) return network_transaction_->Start(request_, callback, net_log); - interceptor_->AddThrottable(this); - int rv = network_transaction_->Start(request_, proxy_callback_, net_log); - return SetupCallback(callback, rv, START); -} - -void DevToolsNetworkTransaction::ProcessRequest(std::string* client_id) { - DCHECK(request_); - bool has_devtools_client_id = request_->extra_headers.HasHeader( - kDevToolsEmulateNetworkConditionsClientId); - if (!has_devtools_client_id) - return; - - custom_request_.reset(new net::HttpRequestInfo(*request_)); - custom_request_->extra_headers.GetHeader( - kDevToolsEmulateNetworkConditionsClientId, client_id); - custom_request_->extra_headers.RemoveHeader( - kDevToolsEmulateNetworkConditionsClientId); - request_ = custom_request_.get(); + int result = network_transaction_->Start(request_, + base::Bind(&DevToolsNetworkTransaction::IOCallback, + base::Unretained(this), callback, true), + net_log); + return Throttle(callback, true, result); } int DevToolsNetworkTransaction::RestartIgnoringLastError( const net::CompletionCallback& callback) { - if (failed_) + if (CheckFailed()) return net::ERR_INTERNET_DISCONNECTED; if (!interceptor_) return network_transaction_->RestartIgnoringLastError(callback); - int rv = network_transaction_->RestartIgnoringLastError(proxy_callback_); - return SetupCallback(callback, rv, RESTART_IGNORING_LAST_ERROR); + + int result = network_transaction_->RestartIgnoringLastError( + base::Bind(&DevToolsNetworkTransaction::IOCallback, + base::Unretained(this), callback, true)); + return Throttle(callback, true, result); } int DevToolsNetworkTransaction::RestartWithCertificate( net::X509Certificate* client_cert, net::SSLPrivateKey* client_private_key, const net::CompletionCallback& callback) { - if (failed_) + if (CheckFailed()) return net::ERR_INTERNET_DISCONNECTED; if (!interceptor_) { return network_transaction_->RestartWithCertificate( client_cert, client_private_key, callback); } - int rv = network_transaction_->RestartWithCertificate( - client_cert, client_private_key, proxy_callback_); - return SetupCallback(callback, rv, RESTART_WITH_CERTIFICATE); + + int result = network_transaction_->RestartWithCertificate( + client_cert, client_private_key, + base::Bind(&DevToolsNetworkTransaction::IOCallback, + base::Unretained(this), callback, true)); + return Throttle(callback, true, result); } int DevToolsNetworkTransaction::RestartWithAuth( const net::AuthCredentials& credentials, const net::CompletionCallback& callback) { - if (failed_) + if (CheckFailed()) return net::ERR_INTERNET_DISCONNECTED; if (!interceptor_) return network_transaction_->RestartWithAuth(credentials, callback); - int rv = network_transaction_->RestartWithAuth(credentials, proxy_callback_); - return SetupCallback(callback, rv, RESTART_WITH_AUTH); + + int result = network_transaction_->RestartWithAuth(credentials, + base::Bind(&DevToolsNetworkTransaction::IOCallback, + base::Unretained(this), callback, true)); + return Throttle(callback, true, result); } bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() { @@ -217,12 +193,18 @@ net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) { - if (failed_) + if (CheckFailed()) return net::ERR_INTERNET_DISCONNECTED; if (!interceptor_) return network_transaction_->Read(buf, buf_len, callback); - int rv = network_transaction_->Read(buf, buf_len, proxy_callback_); - return SetupCallback(callback, rv, READ); + + int result = network_transaction_->Read(buf, buf_len, + base::Bind(&DevToolsNetworkTransaction::IOCallback, + base::Unretained(this), callback, false)); + // URLRequestJob relies on synchronous end-of-stream notification. + if (result == 0) + return result; + return Throttle(callback, false, result); } void DevToolsNetworkTransaction::StopCaching() { @@ -294,10 +276,8 @@ } int DevToolsNetworkTransaction::ResumeNetworkStart() { - if (failed_) + if (CheckFailed()) return net::ERR_INTERNET_DISCONNECTED; - if (!interceptor_) - return network_transaction_->ResumeNetworkStart(); return network_transaction_->ResumeNetworkStart(); } @@ -306,12 +286,3 @@ const { network_transaction_->GetConnectionAttempts(out); } - -void DevToolsNetworkTransaction::ThrottleFinished() { - DCHECK(!callback_.is_null()); - DCHECK(callback_type_ == READ || callback_type_ == START); - net::CompletionCallback callback = callback_; - callback_.Reset(); - callback_type_ = NONE; - callback.Run(throttled_result_); -}
diff --git a/chrome/browser/devtools/devtools_network_transaction.h b/chrome/browser/devtools/devtools_network_transaction.h index ac3efa6b..bb83ce0 100644 --- a/chrome/browser/devtools/devtools_network_transaction.h +++ b/chrome/browser/devtools/devtools_network_transaction.h
@@ -42,8 +42,7 @@ // used to simulate network outage. It runs saved callback (if any) with // net::ERR_INTERNET_DISCONNECTED result value. class DevToolsNetworkTransaction - : public net::HttpTransaction, - public DevToolsNetworkInterceptor::Throttable { + : public net::HttpTransaction { public: static const char kDevToolsEmulateNetworkConditionsClientId[]; @@ -53,13 +52,6 @@ ~DevToolsNetworkTransaction() override; - // DevToolsNetworkInterceptor::Throttable implementation. - void Fail() override; - int64_t ThrottledByteCount() override; - void Throttled(int64_t count) override; - void ThrottleFinished() override; - void GetSendEndTiming(base::TimeTicks* send_end) override; - // HttpTransaction methods: int Start(const net::HttpRequestInfo* request, const net::CompletionCallback& callback, @@ -101,13 +93,21 @@ friend class test::DevToolsNetworkControllerHelper; private: - // Checks whether request contains - // "X-DevTools-Emulate-Network-Conditions-Client-Id" header. - // If it does, header is removed from request, and it's value is returned. - void ProcessRequest(std::string* client_id); + void Fail(); + bool CheckFailed(); - // Proxy callback handler. Runs saved callback. - void OnCallback(int result); + void IOCallback(const net::CompletionCallback& callback, + bool start, + int result); + int Throttle(const net::CompletionCallback& callback, + bool start, + int result); + void ThrottleCallback(const net::CompletionCallback& callback, + int result, + int64_t bytes); + + DevToolsNetworkInterceptor::ThrottleCallback throttle_callback_; + int64_t throttled_byte_count_; DevToolsNetworkController* controller_; base::WeakPtr<DevToolsNetworkInterceptor> interceptor_; @@ -123,31 +123,6 @@ // True if Fail was already invoked. bool failed_; - // Value of request header. - std::string client_id_; - - enum CallbackType { - NONE, - READ, - RESTART_IGNORING_LAST_ERROR, - RESTART_WITH_AUTH, - RESTART_WITH_CERTIFICATE, - START - }; - - int SetupCallback( - net::CompletionCallback callback, - int result, - CallbackType callback_type); - - void Throttle(int result); - - int throttled_result_; - int64_t throttled_byte_count_; - CallbackType callback_type_; - net::CompletionCallback proxy_callback_; - net::CompletionCallback callback_; - DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransaction); };
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc index abe25a8..6b72f14 100644 --- a/chrome/browser/download/download_item_model.cc +++ b/chrome/browser/download/download_item_model.cc
@@ -175,7 +175,6 @@ NOTREACHED(); // fallthrough case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: - case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; } @@ -256,7 +255,6 @@ NOTREACHED(); // fallthrough case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: - case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED: string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS; }
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc index 7fdd128..7c63497 100644 --- a/chrome/browser/download/download_item_model_unittest.cc +++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -156,8 +156,6 @@ "Failed - Server problem" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE, "Failed - Download error" }, - { content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION, - "Failed - Download error" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, "Failed - No file" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED, @@ -234,8 +232,6 @@ "foo.bar\nServer problem" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE, "foo.bar\nDownload error" }, - { content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION, - "foo.bar\nDownload error" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, "foo.bar\nNo file" }, { content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED,
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc index 7e6ce7f6..415b622 100644 --- a/chrome/browser/download/download_query.cc +++ b/chrome/browser/download/download_query.cc
@@ -69,35 +69,6 @@ // The next several functions are helpers for making Callbacks that access // DownloadItem fields. -static bool MatchesQuery( - const std::vector<base::string16>& query_terms, - const DownloadItem& item) { - DCHECK(!query_terms.empty()); - base::string16 url_raw(base::UTF8ToUTF16(item.GetOriginalUrl().spec())); - base::string16 url_formatted = url_raw; - if (item.GetBrowserContext()) { - Profile* profile = Profile::FromBrowserContext(item.GetBrowserContext()); - url_formatted = url_formatter::FormatUrl( - item.GetOriginalUrl(), - profile->GetPrefs()->GetString(prefs::kAcceptLanguages)); - } - base::string16 path(item.GetTargetFilePath().LossyDisplayName()); - - for (std::vector<base::string16>::const_iterator it = query_terms.begin(); - it != query_terms.end(); ++it) { - base::string16 term = base::i18n::ToLower(*it); - if (!base::i18n::StringSearchIgnoringCaseAndAccents( - term, url_raw, NULL, NULL) && - !base::i18n::StringSearchIgnoringCaseAndAccents( - term, url_formatted, NULL, NULL) && - !base::i18n::StringSearchIgnoringCaseAndAccents( - term, path, NULL, NULL)) { - return false; - } - } - return true; -} - static int64 GetStartTimeMsEpoch(const DownloadItem& item) { return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds(); } @@ -237,6 +208,37 @@ } // anonymous namespace +// static +bool DownloadQuery::MatchesQuery(const std::vector<base::string16>& query_terms, + const DownloadItem& item) { + if (query_terms.empty()) + return true; + + base::string16 url_raw(base::UTF8ToUTF16(item.GetOriginalUrl().spec())); + base::string16 url_formatted = url_raw; + if (item.GetBrowserContext()) { + Profile* profile = Profile::FromBrowserContext(item.GetBrowserContext()); + url_formatted = url_formatter::FormatUrl( + item.GetOriginalUrl(), + profile->GetPrefs()->GetString(prefs::kAcceptLanguages)); + } + base::string16 path(item.GetTargetFilePath().LossyDisplayName()); + + for (std::vector<base::string16>::const_iterator it = query_terms.begin(); + it != query_terms.end(); ++it) { + base::string16 term = base::i18n::ToLower(*it); + if (!base::i18n::StringSearchIgnoringCaseAndAccents( + term, url_raw, NULL, NULL) && + !base::i18n::StringSearchIgnoringCaseAndAccents( + term, url_formatted, NULL, NULL) && + !base::i18n::StringSearchIgnoringCaseAndAccents( + term, path, NULL, NULL)) { + return false; + } + } + return true; +} + DownloadQuery::DownloadQuery() : limit_(kuint32max), skip_(0U) {} DownloadQuery::~DownloadQuery() {}
diff --git a/chrome/browser/download/download_query.h b/chrome/browser/download/download_query.h index baa5190c..22ea2bf 100644 --- a/chrome/browser/download/download_query.h +++ b/chrome/browser/download/download_query.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/callback_forward.h" +#include "base/strings/string16.h" #include "content/public/browser/download_item.h" namespace base { @@ -90,6 +91,9 @@ DESCENDING, }; + static bool MatchesQuery(const std::vector<base::string16>& query_terms, + const content::DownloadItem& item); + DownloadQuery(); ~DownloadQuery();
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc index 41bc33e..54f5f1c 100644 --- a/chrome/browser/download/notification/download_item_notification.cc +++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -369,13 +369,12 @@ case content::DownloadItem::IN_PROGRESS: { int percent_complete = item_->PercentComplete(); if (percent_complete >= 0) { - notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); notification_->set_progress(percent_complete); } else { - notification_->set_type( - message_center::NOTIFICATION_TYPE_BASE_FORMAT); - notification_->set_progress(0); + // Negative progress value shows an indeterminate progress bar. + notification_->set_progress(-1); } + notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); break; } case content::DownloadItem::COMPLETE:
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc index 51b7f38..992df31 100644 --- a/chrome/browser/download/notification/download_notification_browsertest.cc +++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/command_line.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" +#include "base/prefs/pref_service.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -18,6 +19,7 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/in_process_browser_test.h" @@ -284,11 +286,43 @@ base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler)); GetMessageCenter()->DisableTimersForTest(); + + // Set up the temporary download folder. + ASSERT_TRUE(CreateAndSetDownloadsDirectory(browser())); + } + + protected: + // Must be called after browser creation. Creates a temporary + // directory for downloads that is auto-deleted on destruction. + // Returning false indicates a failure of the function, and should be asserted + // in the caller. + bool CreateAndSetDownloadsDirectory(Browser* browser) { + if (!browser) + return false; + + if (!downloads_directory_.path().empty()) + return true; // already created + + if (!downloads_directory_.CreateUniqueTempDir()) + return false; + + browser->profile()->GetPrefs()->SetFilePath( + prefs::kDownloadDefaultDirectory, + downloads_directory_.path()); + browser->profile()->GetPrefs()->SetFilePath( + prefs::kSaveFileDefaultDirectory, + downloads_directory_.path()); + + return true; } content::DownloadManager* GetDownloadManager(Browser* browser) { return content::BrowserContext::GetDownloadManager(browser->profile()); } + + private: + // Location of the downloads directory for these tests + base::ScopedTempDir downloads_directory_; }; ////////////////////////////////////////////////// @@ -322,6 +356,8 @@ incognito_browser_ = CreateIncognitoBrowser(); Profile* incognito_profile = incognito_browser_->profile(); + ASSERT_TRUE(CreateAndSetDownloadsDirectory(incognito_browser_)); + scoped_ptr<TestChromeDownloadManagerDelegate> incognito_test_delegate; incognito_test_delegate.reset( new TestChromeDownloadManagerDelegate(incognito_profile)); @@ -385,13 +421,7 @@ std::string notification_id_; }; -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadFile DISABLED_DownloadFile -#else -#define MAYBE_DownloadFile DownloadFile -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DownloadFile) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadFile) { CreateDownload(); EXPECT_EQ(l10n_util::GetStringFUTF16( @@ -443,13 +473,7 @@ EXPECT_FALSE(GetNotification(notification_id())); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadDangerousFile DISABLED_DownloadDangerousFile -#else -#define MAYBE_DownloadDangerousFile DownloadDangerousFile -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DownloadDangerousFile) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadDangerousFile) { GURL download_url(embedded_test_server()->GetURL( "/downloads/dangerous/dangerous.swf")); @@ -500,13 +524,7 @@ EXPECT_TRUE(base::PathExists(GetDownloadPath().Append(filename.BaseName()))); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DiscardDangerousFile DISABLED_DiscardDangerousFile -#else -#define MAYBE_DiscardDangerousFile DiscardDangerousFile -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DiscardDangerousFile) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DiscardDangerousFile) { GURL download_url(embedded_test_server()->GetURL( "/downloads/dangerous/dangerous.swf")); @@ -555,13 +573,7 @@ EXPECT_FALSE(base::PathExists(GetDownloadPath().Append(filename.BaseName()))); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadImageFile DISABLED_DownloadImageFile -#else -#define MAYBE_DownloadImageFile DownloadImageFile -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DownloadImageFile) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadImageFile) { GURL download_url(embedded_test_server()->GetURL( "/downloads/image-octet-stream.png")); @@ -583,14 +595,8 @@ } } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_CloseNotificationAfterDownload DISABLED_CloseNotificationAfterDownload -#else -#define MAYBE_CloseNotificationAfterDownload CloseNotificationAfterDownload -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_CloseNotificationAfterDownload) { + CloseNotificationAfterDownload) { CreateDownload(); // Requests to complete the download. @@ -622,14 +628,8 @@ EXPECT_EQ(content::DownloadItem::COMPLETE, downloads[0]->GetState()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_CloseNotificationWhileDownloading DISABLED_CloseNotificationWhileDownloading -#else -#define MAYBE_CloseNotificationWhileDownloading CloseNotificationWhileDownloading -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_CloseNotificationWhileDownloading) { + CloseNotificationWhileDownloading) { CreateDownload(); // Closes the notification. @@ -668,13 +668,7 @@ EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id())); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_InterruptDownload DISABLED_InterruptDownload -#else -#define MAYBE_InterruptDownload InterruptDownload -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_InterruptDownload) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, InterruptDownload) { CreateDownload(); // Installs observers before requesting. @@ -714,14 +708,8 @@ GetNotification(notification_id())->type()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_InterruptDownloadAfterClosingNotification DISABLED_InterruptDownloadAfterClosingNotification -#else -#define MAYBE_InterruptDownloadAfterClosingNotification InterruptDownloadAfterClosingNotification -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_InterruptDownloadAfterClosingNotification) { + InterruptDownloadAfterClosingNotification) { CreateDownload(); // Closes the notification. @@ -760,13 +748,7 @@ EXPECT_TRUE(IsInNotifications(visible_notifications, notification_id())); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadRemoved DISABLED_DownloadRemoved -#else -#define MAYBE_DownloadRemoved DownloadRemoved -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DownloadRemoved) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadRemoved) { CreateDownload(); NotificationRemoveObserver notification_close_observer; @@ -782,13 +764,7 @@ EXPECT_EQ(0u, downloads.size()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadMultipleFiles DISABLED_DownloadMultipleFiles -#else -#define MAYBE_DownloadMultipleFiles DownloadMultipleFiles -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_DownloadMultipleFiles) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadMultipleFiles) { GURL url1(net::URLRequestSlowDownloadJob::kUnknownSizeUrl); GURL url2(net::URLRequestSlowDownloadJob::kKnownSizeUrl); @@ -920,14 +896,8 @@ GetNotification(notification_id2)->type()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadMultipleFilesOneByOne DISABLED_DownloadMultipleFilesOneByOne -#else -#define MAYBE_DownloadMultipleFilesOneByOne DownloadMultipleFilesOneByOne -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_DownloadMultipleFilesOneByOne) { + DownloadMultipleFilesOneByOne) { CreateDownload(); content::DownloadItem* first_download_item = download_item(); content::DownloadItem* second_download_item = nullptr; @@ -1003,13 +973,7 @@ EXPECT_EQ(2u, GetMessageCenter()->GetVisibleNotifications().size()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_CancelDownload DISABLED_CancelDownload -#else -#define MAYBE_CancelDownload CancelDownload -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_CancelDownload) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, CancelDownload) { CreateDownload(); // Opens the message center. @@ -1028,14 +992,8 @@ EXPECT_EQ(content::DownloadItem::CANCELLED, downloads[0]->GetState()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadCancelledByUserExternally DISABLED_DownloadCancelledByUserExternally -#else -#define MAYBE_DownloadCancelledByUserExternally DownloadCancelledByUserExternally -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_DownloadCancelledByUserExternally) { + DownloadCancelledByUserExternally) { CreateDownload(); // Cancels the notification by clicking the "cancel' button. @@ -1051,14 +1009,8 @@ EXPECT_EQ(content::DownloadItem::CANCELLED, downloads[0]->GetState()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_DownloadCancelledExternally DISABLED_DownloadCancelledExternally -#else -#define MAYBE_DownloadCancelledExternally DownloadCancelledExternally -#endif IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, - MAYBE_DownloadCancelledExternally) { + DownloadCancelledExternally) { CreateDownload(); // Cancels the notification by clicking the "cancel' button. @@ -1074,13 +1026,7 @@ EXPECT_EQ(content::DownloadItem::CANCELLED, downloads[0]->GetState()); } -// TODO(yoshiki): Disabled due to crbug.com/560329 -#if defined(OS_CHROMEOS) -#define MAYBE_IncognitoDownloadFile DISABLED_IncognitoDownloadFile -#else -#define MAYBE_IncognitoDownloadFile IncognitoDownloadFile -#endif -IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, MAYBE_IncognitoDownloadFile) { +IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, IncognitoDownloadFile) { PrepareIncognitoBrowser(); // Starts an incognito download. @@ -1179,7 +1125,7 @@ EXPECT_EQ(download_incognito, downloads[0]); // Confirms the types of download notifications are correct. - EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, + EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, GetNotification(notification_id1)->type()); EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, GetNotification(notification_id2)->type()); @@ -1202,8 +1148,10 @@ // Confirms the types of download notifications are correct. EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, GetNotification(notification_id1)->type()); + EXPECT_EQ(-1, GetNotification(notification_id1)->progress()); EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, GetNotification(notification_id2)->type()); + EXPECT_LE(0, GetNotification(notification_id1)->progress()); chrome::CloseWindow(incognito_browser()); } @@ -1335,13 +1283,16 @@ // Confirms the types of download notifications are correct. // Normal notification for user1. - EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, + EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, GetNotification(notification_id_user1)->type()); + EXPECT_EQ(-1, GetNotification(notification_id_user1)->progress()); // Normal notification for user2. - EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, + EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, GetNotification(notification_id_user2_1)->type()); - EXPECT_EQ(message_center::NOTIFICATION_TYPE_BASE_FORMAT, + EXPECT_EQ(-1, GetNotification(notification_id_user2_1)->progress()); + EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, GetNotification(notification_id_user2_2)->type()); + EXPECT_EQ(-1, GetNotification(notification_id_user2_2)->progress()); // Requests to complete the downloads. NotificationUpdateObserver download_change_notification_observer;
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc index dee238d..7650679 100644 --- a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc +++ b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc
@@ -4,9 +4,7 @@ #include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h" -#include "base/atomicops.h" #include "base/command_line.h" -#include "base/strings/string_number_conversions.h" #include "chrome/common/chrome_content_client.h" #include "net/base/net_errors.h" #include "net/cert/cert_verifier.h" @@ -17,11 +15,6 @@ namespace extensions { -namespace { -// TODO(vitalybuka): crbug.com/458365 Move into URLRequestContextBuilder -base::subtle::Atomic32 g_ssl_shard_counter = 0; -} - // Class verifies certificate by its fingerprint received using different // channel. It's the only know information about device with self-signed // certificate. @@ -109,10 +102,7 @@ DCHECK(net_task_runner_->BelongsToCurrentThread()); if (!context_) { net::URLRequestContextBuilder builder; - std::string shard_name = "privet_v3_context_getter/"; - shard_name += base::IntToString( - base::subtle::Barrier_AtomicIncrement(&g_ssl_shard_counter, 1)); - builder.set_ssl_session_cache_shard(shard_name); + builder.set_proxy_service(net::ProxyService::CreateDirect()); builder.SetSpdyAndQuicEnabled(false, false); builder.DisableHttpCache();
diff --git a/chrome/browser/extensions/extension_fullscreen_apitest.cc b/chrome/browser/extensions/extension_fullscreen_apitest.cc index e7794a3..57536e3 100644 --- a/chrome/browser/extensions/extension_fullscreen_apitest.cc +++ b/chrome/browser/extensions/extension_fullscreen_apitest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExtensionFullscreenAccessFail) { @@ -26,7 +28,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FocusWindowDoesNotExitFullscreen) { - browser()->window()->EnterFullscreen( + browser()->exclusive_access_manager()->context()->EnterFullscreen( GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION, false); ASSERT_TRUE(browser()->window()->IsFullscreen()); @@ -43,7 +45,7 @@ #endif // defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_UpdateWindowSizeExitsFullscreen) { - browser()->window()->EnterFullscreen( + browser()->exclusive_access_manager()->context()->EnterFullscreen( GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION, false); ASSERT_TRUE(RunExtensionTest("window_update/sizing")) << message_;
diff --git a/chrome/browser/extensions/updater/local_extension_cache_unittest.cc b/chrome/browser/extensions/updater/local_extension_cache_unittest.cc index 3fe8a2b..6dcda932 100644 --- a/chrome/browser/extensions/updater/local_extension_cache_unittest.cc +++ b/chrome/browser/extensions/updater/local_extension_cache_unittest.cc
@@ -48,11 +48,6 @@ pool_owner_->pool()->GetNamedSequenceToken("background")); } - void TearDown() override { - pool_owner_->pool()->Shutdown(); - base::RunLoop().RunUntilIdle(); - } - base::FilePath CreateCacheDir(bool initialized) { EXPECT_TRUE(cache_dir_.CreateUniqueTempDir()); if (initialized)
diff --git a/chrome/browser/interstitials/chrome_controller_client.cc b/chrome/browser/interstitials/chrome_controller_client.cc index 01c1be72..c39e2a5 100644 --- a/chrome/browser/interstitials/chrome_controller_client.cc +++ b/chrome/browser/interstitials/chrome_controller_client.cc
@@ -4,21 +4,162 @@ #include "chrome/browser/interstitials/chrome_controller_client.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_util.h" #include "base/prefs/pref_service.h" +#include "base/process/launch.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/interstitial_page.h" #include "content/public/browser/web_contents.h" #include "content/public/common/referrer.h" +#if defined(OS_ANDROID) +#include "chrome/browser/android/intent_helper.h" +#endif + +#if defined(OS_CHROMEOS) +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/chrome_pages.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#endif + +#if defined(OS_WIN) +#include "base/base_paths_win.h" +#include "base/path_service.h" +#include "base/strings/string16.h" +#include "base/win/windows_version.h" +#endif + using content::Referrer; +namespace { + +void LaunchDateAndTimeSettingsOnFile() { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); +// The code for each OS is completely separate, in order to avoid bugs like +// https://crbug.com/430877 . +#if defined(OS_ANDROID) + chrome::android::OpenDateAndTimeSettings(); + +#elif defined(OS_CHROMEOS) + std::string sub_page = + std::string(chrome::kSearchSubPage) + "#" + + l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME); + chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(), + sub_page); + +#elif defined(OS_IOS) + // TODO(blundell): Remove this once iOS has its own version of this class. + // iOS does not have a way to launch the date and time settings. + NOTREACHED(); + +#elif defined(OS_LINUX) + struct ClockCommand { + const char* pathname; + const char* argument; + }; + static const ClockCommand kClockCommands[] = { + // Unity + {"/usr/bin/unity-control-center", "datetime"}, + // GNOME + // + // NOTE: On old Ubuntu, naming control panels doesn't work, so it + // opens the overview. This will have to be good enough. + {"/usr/bin/gnome-control-center", "datetime"}, + {"/usr/local/bin/gnome-control-center", "datetime"}, + {"/opt/bin/gnome-control-center", "datetime"}, + // KDE + {"/usr/bin/kcmshell4", "clock"}, + {"/usr/local/bin/kcmshell4", "clock"}, + {"/opt/bin/kcmshell4", "clock"}, + }; + + base::CommandLine command(base::FilePath("")); + for (const ClockCommand& cmd : kClockCommands) { + base::FilePath pathname(cmd.pathname); + if (base::PathExists(pathname)) { + command.SetProgram(pathname); + command.AppendArg(cmd.argument); + break; + } + } + if (command.GetProgram().empty()) { + // Alas, there is nothing we can do. + return; + } + + base::LaunchOptions options; + options.wait = false; + options.allow_new_privs = true; + base::LaunchProcess(command, options); + +#elif defined(OS_MACOSX) + base::CommandLine command(base::FilePath("/usr/bin/open")); + command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane"); + + base::LaunchOptions options; + options.wait = false; + base::LaunchProcess(command, options); + +#elif defined(OS_WIN) + base::FilePath path; + PathService::Get(base::DIR_SYSTEM, &path); + static const base::char16 kControlPanelExe[] = L"control.exe"; + path = path.Append(base::string16(kControlPanelExe)); + base::CommandLine command(path); + command.AppendArg(std::string("/name")); + command.AppendArg(std::string("Microsoft.DateAndTime")); + + base::LaunchOptions options; + options.wait = false; + base::LaunchProcess(command, options); + +#else + NOTREACHED(); + +#endif + // Don't add code here! (See the comment at the beginning of the function.) +} + +} // namespace + ChromeControllerClient::ChromeControllerClient( content::WebContents* web_contents) - : web_contents_(web_contents) {} + : web_contents_(web_contents), interstitial_page_(nullptr) {} ChromeControllerClient::~ChromeControllerClient() {} +void ChromeControllerClient::set_interstitial_page( + content::InterstitialPage* interstitial_page) { + interstitial_page_ = interstitial_page; +} + +bool ChromeControllerClient::CanLaunchDateAndTimeSettings() { +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \ + defined(OS_MACOSX) || defined(OS_WIN) + return true; +#else + return false; +#endif +} + +void ChromeControllerClient::LaunchDateAndTimeSettings() { + content::BrowserThread::PostTask( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&LaunchDateAndTimeSettingsOnFile)); +} + +void ChromeControllerClient::GoBack() { + DCHECK(interstitial_page_); + interstitial_page_->DontProceed(); +} + void ChromeControllerClient::OpenUrlInCurrentTab(const GURL& url) { content::OpenURLParams params(url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_LINK, false);
diff --git a/chrome/browser/interstitials/chrome_controller_client.h b/chrome/browser/interstitials/chrome_controller_client.h index 3634233..325296f 100644 --- a/chrome/browser/interstitials/chrome_controller_client.h +++ b/chrome/browser/interstitials/chrome_controller_client.h
@@ -9,6 +9,7 @@ #include "components/security_interstitials/core/controller_client.h" namespace content { +class InterstitialPage; class WebContents; } @@ -18,6 +19,13 @@ explicit ChromeControllerClient(content::WebContents* web_contents); ~ChromeControllerClient() override; + void set_interstitial_page(content::InterstitialPage* interstitial_page); + + // security_interstitials::ControllerClient overrides + bool CanLaunchDateAndTimeSettings() override; + void LaunchDateAndTimeSettings() override; + void GoBack() override; + protected: // security_interstitials::ControllerClient overrides void OpenUrlInCurrentTab(const GURL& url) override; @@ -27,6 +35,7 @@ private: content::WebContents* web_contents_; + content::InterstitialPage* interstitial_page_; DISALLOW_COPY_AND_ASSIGN(ChromeControllerClient); };
diff --git a/chrome/browser/interstitials/security_interstitial_page.cc b/chrome/browser/interstitials/security_interstitial_page.cc index fd26268..48bbcf5 100644 --- a/chrome/browser/interstitials/security_interstitial_page.cc +++ b/chrome/browser/interstitials/security_interstitial_page.cc
@@ -17,8 +17,8 @@ #include "chrome/grit/browser_resources.h" #include "chrome/grit/generated_resources.h" #include "components/grit/components_resources.h" +#include "components/security_interstitials/core/common_string_util.h" #include "components/security_interstitials/core/metrics_helper.h" -#include "components/url_formatter/url_formatter.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/page_navigator.h" #include "content/public/browser/web_contents.h" @@ -65,6 +65,9 @@ if (!create_view_) interstitial_page_->DontCreateViewForTesting(); interstitial_page_->Show(); + + controller_->set_interstitial_page(interstitial_page_); + AfterShow(); } bool SecurityInterstitialPage::IsPrefEnabled(const char* pref) { @@ -79,11 +82,8 @@ Profile::FromBrowserContext(web_contents()->GetBrowserContext()); if (profile) languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages); - base::string16 host = - url_formatter::IDNToUnicode(request_url_.host(), languages); - if (base::i18n::IsRTL()) - base::i18n::WrapStringWithLTRFormatting(&host); - return host; + return security_interstitials::common_string_util::GetFormattedHostName( + request_url_, languages); } std::string SecurityInterstitialPage::GetHTMLContents() {
diff --git a/chrome/browser/interstitials/security_interstitial_page.h b/chrome/browser/interstitials/security_interstitial_page.h index 914e096d..471c1e2 100644 --- a/chrome/browser/interstitials/security_interstitial_page.h +++ b/chrome/browser/interstitials/security_interstitial_page.h
@@ -44,6 +44,10 @@ virtual void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) = 0; + // Gives an opportunity for child classes to react to Show() having run. The + // interstitial_page_ will now have a value. + virtual void AfterShow() = 0; + // InterstitialPageDelegate method: std::string GetHTMLContents() override;
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 595057a..e581281 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -993,17 +993,6 @@ return io_data_->GetMediaDeviceIDSalt(); } -// static -std::string ProfileIOData::GetSSLSessionCacheShard() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // The SSL session cache is partitioned by setting a string. This returns a - // unique string to partition the SSL session cache. Each time we create a - // new profile, we'll get a fresh SSL session cache which is separate from - // the other profiles. - static unsigned ssl_session_cache_instance = 0; - return base::StringPrintf("profile/%u", ssl_session_cache_instance++); -} - void ProfileIOData::Init( content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) const { @@ -1304,8 +1293,6 @@ io_thread->InitializeNetworkSessionParams(¶ms); net::URLRequestContextBuilder::SetHttpNetworkSessionComponents(context, ¶ms); - - params.ssl_session_cache_shard = GetSSLSessionCacheShard(); if (!IsOffTheRecord()) { params.socket_performance_watcher_factory = io_thread->globals()->network_quality_estimator.get();
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h index eb27c12..20c7e77 100644 --- a/chrome/browser/profiles/profile_io_data.h +++ b/chrome/browser/profiles/profile_io_data.h
@@ -329,8 +329,6 @@ explicit ProfileIOData(Profile::ProfileType profile_type); - static std::string GetSSLSessionCacheShard(); - void InitializeOnUIThread(Profile* profile); void ApplyProfileParamsToContext(net::URLRequestContext* context) const;
diff --git a/chrome/browser/resources/md_downloads/action_service.js b/chrome/browser/resources/md_downloads/action_service.js index f984fe5..ee0a1b4 100644 --- a/chrome/browser/resources/md_downloads/action_service.js +++ b/chrome/browser/resources/md_downloads/action_service.js
@@ -14,6 +14,27 @@ /** @constructor */ function ActionService() {} + /** + * @param {string} s + * @return {string} |s| without whitespace at the beginning or end. + */ + function trim(s) { return s.trim(); } + + /** + * @param {string|undefined} value + * @return {boolean} Whether |value| is truthy. + */ + function truthy(value) { return !!value; } + + /** + * @param {string} searchText Input typed by the user into a search box. + * @return {Array<string>} A list of terms extracted from |searchText|. + */ + ActionService.splitTerms = function(searchText) { + // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). + return searchText.split(/"([^"]*)"/).map(trim).filter(truthy); + }; + ActionService.prototype = { /** @param {string} id ID of the download to cancel. */ cancel: chromeSendWithId('cancel'), @@ -40,12 +61,15 @@ /** @param {string} id ID of the download that the user started dragging. */ drag: chromeSendWithId('drag'), + /** @private {boolean} */ + isSearching_: false, + /** * @return {boolean} Whether the user is currently searching for downloads * (i.e. has a non-empty search term). */ isSearching: function() { - return this.searchText_.length > 0; + return this.isSearching_; }, /** Opens the current local destination for downloads. */ @@ -78,9 +102,10 @@ this.searchText_ = searchText; - // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). - function trim(s) { return s.trim(); } - chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim)); + var terms = ActionService.splitTerms(searchText); + this.isSearching_ = terms.length > 0; + + chrome.send('getDownloads', terms); }, /**
diff --git a/chrome/browser/resources/md_downloads/crisper.js b/chrome/browser/resources/md_downloads/crisper.js index da445238..ee13e9c 100644 --- a/chrome/browser/resources/md_downloads/crisper.js +++ b/chrome/browser/resources/md_downloads/crisper.js
@@ -1531,6 +1531,27 @@ /** @constructor */ function ActionService() {} + /** + * @param {string} s + * @return {string} |s| without whitespace at the beginning or end. + */ + function trim(s) { return s.trim(); } + + /** + * @param {string|undefined} value + * @return {boolean} Whether |value| is truthy. + */ + function truthy(value) { return !!value; } + + /** + * @param {string} searchText Input typed by the user into a search box. + * @return {Array<string>} A list of terms extracted from |searchText|. + */ + ActionService.splitTerms = function(searchText) { + // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). + return searchText.split(/"([^"]*)"/).map(trim).filter(truthy); + }; + ActionService.prototype = { /** @param {string} id ID of the download to cancel. */ cancel: chromeSendWithId('cancel'), @@ -1557,12 +1578,15 @@ /** @param {string} id ID of the download that the user started dragging. */ drag: chromeSendWithId('drag'), + /** @private {boolean} */ + isSearching_: false, + /** * @return {boolean} Whether the user is currently searching for downloads * (i.e. has a non-empty search term). */ isSearching: function() { - return this.searchText_.length > 0; + return this.isSearching_; }, /** Opens the current local destination for downloads. */ @@ -1595,9 +1619,10 @@ this.searchText_ = searchText; - // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). - function trim(s) { return s.trim(); } - chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim)); + var terms = ActionService.splitTerms(searchText); + this.isSearching_ = terms.length > 0; + + chrome.send('getDownloads', terms); }, /** @@ -16937,12 +16962,13 @@ properties: { hasDownloads_: { + observer: 'hasDownloadsChanged_', type: Boolean, - value: false, }, items_: { type: Array, + value: function() { return []; }, }, }, @@ -16950,6 +16976,46 @@ loading: true, }, + observers: [ + 'itemsChanged_(items_.*)', + ], + + /** @private */ + clearAll_: function() { + this.set('items_', []); + }, + + /** @private */ + hasDownloadsChanged_: function() { + if (loadTimeData.getBoolean('allowDeletingHistory')) + this.$.toolbar.downloadsShowing = this.hasDownloads_; + + if (this.hasDownloads_) { + this.$['downloads-list'].fire('iron-resize'); + } else { + var isSearching = downloads.ActionService.getInstance().isSearching(); + var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads'; + this.$['no-downloads'].querySelector('span').textContent = + loadTimeData.getString(messageToShow); + } + }, + + /** + * @param {number} index + * @param {!Array<!downloads.Data>} list + * @private + */ + insertItems_: function(index, list) { + this.splice.apply(this, ['items_', index, 0].concat(list)); + this.updateHideDates_(index, index + list.length); + this.removeAttribute('loading'); + }, + + /** @private */ + itemsChanged_: function() { + this.hasDownloads_ = this.items_.length > 0; + }, + /** * @param {Event} e * @private @@ -16988,78 +17054,65 @@ }, /** - * @return {number} The number of downloads shown on the page. + * @param {number} index * @private */ - size_: function() { - return this.items_.length; + removeItem_: function(index) { + this.splice('items_', index, 1); + this.updateHideDates_(index, index); }, /** - * Called when all items need to be updated. - * @param {!Array<!downloads.Data>} list A list of new download data. + * @param {number} start + * @param {number} end * @private */ - updateAll_: function(list) { - /** @private {!Object<number>} */ - this.idToIndex_ = {}; - - for (var i = 0; i < list.length; ++i) { - var data = list[i]; - - this.idToIndex_[data.id] = data.index = i; - - var prev = list[i - 1]; - data.hideDate = !!prev && prev.date_string == data.date_string; + updateHideDates_: function(start, end) { + for (var i = start; i <= end; ++i) { + var current = this.items_[i]; + if (!current) + continue; + var prev = this.items_[i - 1]; + current.hideDate = !!prev && prev.date_string == current.date_string; } - - // TODO(dbeam): this resets the scroll position, which is a huge bummer. - // Removing something from the bottom of the list should not scroll you - // back to the top. The grand plan is to restructure how the C++ sends the - // JS data so that it only gets updates (rather than the most recent set - // of items). TL;DR - we can't ship with this bug. - this.items_ = list; - - var hasDownloads = this.size_() > 0; - if (!hasDownloads) { - var isSearching = downloads.ActionService.getInstance().isSearching(); - var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads'; - this.$['no-downloads'].querySelector('span').textContent = - loadTimeData.getString(messageToShow); - } - this.hasDownloads_ = hasDownloads; - - if (loadTimeData.getBoolean('allowDeletingHistory')) - this.$.toolbar.downloadsShowing = this.hasDownloads_; - - this.removeAttribute('loading'); }, /** + * @param {number} index * @param {!downloads.Data} data * @private */ - updateItem_: function(data) { - var index = this.idToIndex_[data.id]; + updateItem_: function(index, data) { this.set('items_.' + index, data); + this.updateHideDates_(index, index); this.$['downloads-list'].updateSizeForItem(index); }, }); - Manager.size = function() { - return document.querySelector('downloads-manager').size_(); + Manager.clearAll = function() { + Manager.get().clearAll_(); }; - Manager.updateAll = function(list) { - document.querySelector('downloads-manager').updateAll_(list); + /** @return {!downloads.Manager} */ + Manager.get = function() { + return /** @type {!downloads.Manager} */( + queryRequiredElement('downloads-manager')); }; - Manager.updateItem = function(item) { - document.querySelector('downloads-manager').updateItem_(item); + Manager.insertItems = function(index, list) { + Manager.get().insertItems_(index, list); }; Manager.onLoad = function() { - document.querySelector('downloads-manager').onLoad_(); + Manager.get().onLoad_(); + }; + + Manager.removeItem = function(index) { + Manager.get().removeItem_(index); + }; + + Manager.updateItem = function(index, data) { + Manager.get().updateItem_(index, data); }; return {Manager: Manager};
diff --git a/chrome/browser/resources/md_downloads/i18n.html b/chrome/browser/resources/md_downloads/i18n.html new file mode 100644 index 0000000..1db516c --- /dev/null +++ b/chrome/browser/resources/md_downloads/i18n.html
@@ -0,0 +1,2 @@ +<script src="chrome://resources/js/load_time_data.js"></script> +<script src="chrome://downloads/strings.js"></script>
diff --git a/chrome/browser/resources/md_downloads/manager.html b/chrome/browser/resources/md_downloads/manager.html index d1b2fa7..159a0d5 100644 --- a/chrome/browser/resources/md_downloads/manager.html +++ b/chrome/browser/resources/md_downloads/manager.html
@@ -23,7 +23,7 @@ <div id="no-downloads" hidden="[[hasDownloads_]]"> <div> <div class="illustration"></div> - <span><!-- Text populated in Manager#updateAll_(). --></span> + <span><!-- Text populated dynamically. --></span> </div> </div> </template>
diff --git a/chrome/browser/resources/md_downloads/manager.js b/chrome/browser/resources/md_downloads/manager.js index 76017ac..91faf6a1 100644 --- a/chrome/browser/resources/md_downloads/manager.js +++ b/chrome/browser/resources/md_downloads/manager.js
@@ -8,12 +8,13 @@ properties: { hasDownloads_: { + observer: 'hasDownloadsChanged_', type: Boolean, - value: false, }, items_: { type: Array, + value: function() { return []; }, }, }, @@ -21,6 +22,46 @@ loading: true, }, + observers: [ + 'itemsChanged_(items_.*)', + ], + + /** @private */ + clearAll_: function() { + this.set('items_', []); + }, + + /** @private */ + hasDownloadsChanged_: function() { + if (loadTimeData.getBoolean('allowDeletingHistory')) + this.$.toolbar.downloadsShowing = this.hasDownloads_; + + if (this.hasDownloads_) { + this.$['downloads-list'].fire('iron-resize'); + } else { + var isSearching = downloads.ActionService.getInstance().isSearching(); + var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads'; + this.$['no-downloads'].querySelector('span').textContent = + loadTimeData.getString(messageToShow); + } + }, + + /** + * @param {number} index + * @param {!Array<!downloads.Data>} list + * @private + */ + insertItems_: function(index, list) { + this.splice.apply(this, ['items_', index, 0].concat(list)); + this.updateHideDates_(index, index + list.length); + this.removeAttribute('loading'); + }, + + /** @private */ + itemsChanged_: function() { + this.hasDownloads_ = this.items_.length > 0; + }, + /** * @param {Event} e * @private @@ -59,78 +100,65 @@ }, /** - * @return {number} The number of downloads shown on the page. + * @param {number} index * @private */ - size_: function() { - return this.items_.length; + removeItem_: function(index) { + this.splice('items_', index, 1); + this.updateHideDates_(index, index); }, /** - * Called when all items need to be updated. - * @param {!Array<!downloads.Data>} list A list of new download data. + * @param {number} start + * @param {number} end * @private */ - updateAll_: function(list) { - /** @private {!Object<number>} */ - this.idToIndex_ = {}; - - for (var i = 0; i < list.length; ++i) { - var data = list[i]; - - this.idToIndex_[data.id] = data.index = i; - - var prev = list[i - 1]; - data.hideDate = !!prev && prev.date_string == data.date_string; + updateHideDates_: function(start, end) { + for (var i = start; i <= end; ++i) { + var current = this.items_[i]; + if (!current) + continue; + var prev = this.items_[i - 1]; + current.hideDate = !!prev && prev.date_string == current.date_string; } - - // TODO(dbeam): this resets the scroll position, which is a huge bummer. - // Removing something from the bottom of the list should not scroll you - // back to the top. The grand plan is to restructure how the C++ sends the - // JS data so that it only gets updates (rather than the most recent set - // of items). TL;DR - we can't ship with this bug. - this.items_ = list; - - var hasDownloads = this.size_() > 0; - if (!hasDownloads) { - var isSearching = downloads.ActionService.getInstance().isSearching(); - var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads'; - this.$['no-downloads'].querySelector('span').textContent = - loadTimeData.getString(messageToShow); - } - this.hasDownloads_ = hasDownloads; - - if (loadTimeData.getBoolean('allowDeletingHistory')) - this.$.toolbar.downloadsShowing = this.hasDownloads_; - - this.removeAttribute('loading'); }, /** + * @param {number} index * @param {!downloads.Data} data * @private */ - updateItem_: function(data) { - var index = this.idToIndex_[data.id]; + updateItem_: function(index, data) { this.set('items_.' + index, data); + this.updateHideDates_(index, index); this.$['downloads-list'].updateSizeForItem(index); }, }); - Manager.size = function() { - return document.querySelector('downloads-manager').size_(); + Manager.clearAll = function() { + Manager.get().clearAll_(); }; - Manager.updateAll = function(list) { - document.querySelector('downloads-manager').updateAll_(list); + /** @return {!downloads.Manager} */ + Manager.get = function() { + return /** @type {!downloads.Manager} */( + queryRequiredElement('downloads-manager')); }; - Manager.updateItem = function(item) { - document.querySelector('downloads-manager').updateItem_(item); + Manager.insertItems = function(index, list) { + Manager.get().insertItems_(index, list); }; Manager.onLoad = function() { - document.querySelector('downloads-manager').onLoad_(); + Manager.get().onLoad_(); + }; + + Manager.removeItem = function(index) { + Manager.get().removeItem_(index); + }; + + Manager.updateItem = function(index, data) { + Manager.get().updateItem_(index, data); }; return {Manager: Manager};
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.js b/chrome/browser/resources/settings/controls/settings_checkbox.js index e892fb9..d0bbebc 100644 --- a/chrome/browser/resources/settings/controls/settings_checkbox.js +++ b/chrome/browser/resources/settings/controls/settings_checkbox.js
@@ -87,7 +87,16 @@ * @private */ checkedChanged_: function() { - this.set('pref.value', this.getNewValue_(this.checked)); + if (!this.pref) + return; + /** @type {boolean} */ var newValue = this.getNewValue_(this.checked); + // Ensure that newValue is the correct type for the pref type, either + // a boolean or a number. + if (this.pref.type == chrome.settingsPrivate.PrefType.NUMBER) { + this.set('pref.value', newValue ? 1 : 0); + return; + } + this.set('pref.value', newValue); }, /**
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h index fd26926..8c8e698 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -107,6 +107,7 @@ bool ShouldCreateNewNavigation() const override; void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) override; + void AfterShow() override {} // After a safe browsing interstitial where the user opted-in to the // report but clicked "proceed anyway", we delay the call to
diff --git a/chrome/browser/safe_browsing/signature_evaluator_mac.mm b/chrome/browser/safe_browsing/signature_evaluator_mac.mm index 3189619..6f64eae 100644 --- a/chrome/browser/safe_browsing/signature_evaluator_mac.mm +++ b/chrome/browser/safe_browsing/signature_evaluator_mac.mm
@@ -13,6 +13,7 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" +#include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "chrome/common/safe_browsing/binary_feature_extractor.h" #include "chrome/common/safe_browsing/csd.pb.h" @@ -34,6 +35,9 @@ "com.apple.cs.CodeEntitlements", }; +// The name of the localization strings file. +const char kStringsFile[] = ".lproj/InfoPlist.strings"; + // Convenience function to get the appropriate path from a variety of NSObject // types. For resources, code signing seems to give back an NSURL in which // the path is relative to the bundle root. So in this case, we take the @@ -106,6 +110,12 @@ relative_path = path.BaseName().value(); } + // Filter out certain noise reports on the client side. + if (base::EndsWith(relative_path, kStringsFile, + base::CompareCase::INSENSITIVE_ASCII)) { + return; + } + ClientIncidentReport_IncidentData_BinaryIntegrityIncident_ContainedFile* contained_file = incident->add_contained_file(); contained_file->set_relative_path(relative_path); @@ -200,6 +210,7 @@ // We heuristically detect if we are in a bundle or not by checking if // the main executable is different from the path_. base::ScopedCFTypeRef<CFDictionaryRef> info_dict; + base::FilePath exec_path; if (SecCodeCopySigningInformation(code_, kSecCSDefaultFlags, info_dict.InitializeInto()) == errSecSuccess) { @@ -208,7 +219,7 @@ if (!exec_url) return false; - base::FilePath exec_path( + exec_path = base::FilePath( [[base::mac::CFToNSCast(exec_url) path] fileSystemRepresentation]); if (exec_path != path_) { ReportAlteredFiles(base::mac::CFToNSCast(exec_url), path_, incident); @@ -229,6 +240,18 @@ ReportAlteredFiles(detail, path_, incident); } } + + // Some resource violations (localizations) are skipped, so if the error is + // that a sealed resource is missing or invalid, and there are no contained + // files aside from the main executable, do not send the report. + if (err == errSecCSBadResource && incident->contained_file_size() == 1) { + if (base::EndsWith(exec_path.value(), + incident->contained_file(0).relative_path(), + base::CompareCase::INSENSITIVE_ASCII)) { + return true; + } + } + return false; }
diff --git a/chrome/browser/safe_browsing/signature_evaluator_mac_unittest.cc b/chrome/browser/safe_browsing/signature_evaluator_mac_unittest.cc index 48843f05..73f9695 100644 --- a/chrome/browser/safe_browsing/signature_evaluator_mac_unittest.cc +++ b/chrome/browser/safe_browsing/signature_evaluator_mac_unittest.cc
@@ -203,6 +203,19 @@ EXPECT_TRUE(contained_file.has_image_headers()); } +TEST_F(MacSignatureEvaluatorTest, ModifiedLocalizationTest) { + // We want to ignore modifications made to InfoPlist.strings files. + base::FilePath path = testdata_path_.AppendASCII("modified-localization.app"); + + std::string requirement( + "certificate leaf[subject.CN]=\"untrusted@goat.local\""); + MacSignatureEvaluator evaluator(path, requirement); + ASSERT_TRUE(evaluator.Initialize()); + + ClientIncidentReport_IncidentData_BinaryIntegrityIncident incident; + EXPECT_TRUE(evaluator.PerformEvaluation(&incident)); +} + TEST_F(MacSignatureEvaluatorTest, ModifiedBundleAndExecTest) { // Now test a modified, signed bundle with resources added and the main // executable modified.
diff --git a/chrome/browser/ssl/bad_clock_blocking_page.cc b/chrome/browser/ssl/bad_clock_blocking_page.cc index a3b3a7b..420045a 100644 --- a/chrome/browser/ssl/bad_clock_blocking_page.cc +++ b/chrome/browser/ssl/bad_clock_blocking_page.cc
@@ -4,34 +4,19 @@ #include "chrome/browser/ssl/bad_clock_blocking_page.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/build_time.h" #include "base/callback_helpers.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/i18n/rtl.h" -#include "base/i18n/time_formatting.h" -#include "base/process/launch.h" +#include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "base/values.h" -#include "chrome/browser/browser_process.h" +#include "chrome/browser/interstitials/chrome_controller_client.h" #include "chrome/browser/interstitials/chrome_metrics_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_preferences_util.h" #include "chrome/browser/ssl/cert_report_helper.h" #include "chrome/browser/ssl/ssl_cert_reporter.h" #include "chrome/common/pref_names.h" -#include "chrome/grit/generated_resources.h" -#include "components/google/core/browser/google_util.h" +#include "components/security_interstitials/core/bad_clock_ui.h" #include "components/security_interstitials/core/controller_client.h" -#include "components/ssl_errors/error_classification.h" -#include "content/public/browser/browser_thread.h" +#include "components/security_interstitials/core/metrics_helper.h" #include "content/public/browser/cert_store.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/interstitial_page_delegate.h" @@ -43,33 +28,8 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/renderer_preferences.h" #include "content/public/common/ssl_status.h" -#include "grit/browser_resources.h" -#include "grit/components_strings.h" #include "net/base/net_errors.h" -#include "net/base/net_util.h" -#include "net/cert/x509_certificate.h" -#include "ui/base/l10n/l10n_util.h" -#if defined(OS_ANDROID) -#include "chrome/browser/android/intent_helper.h" -#endif - -#if defined(OS_CHROMEOS) -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/chrome_pages.h" -#include "chrome/common/url_constants.h" -#endif - -#if defined(OS_WIN) -#include "base/base_paths_win.h" -#include "base/path_service.h" -#include "base/strings/string16.h" -#include "base/win/windows_version.h" -#endif - -using base::ASCIIToUTF16; -using base::TimeTicks; -using content::InterstitialPage; using content::InterstitialPageDelegate; using content::NavigationController; using content::NavigationEntry; @@ -78,92 +38,6 @@ const char kMetricsName[] = "bad_clock"; -void LaunchDateAndTimeSettings() { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); -// The code for each OS is completely separate, in order to avoid bugs like -// https://crbug.com/430877 . -#if defined(OS_ANDROID) - chrome::android::OpenDateAndTimeSettings(); - -#elif defined(OS_CHROMEOS) - std::string sub_page = - std::string(chrome::kSearchSubPage) + "#" + - l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME); - chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(), - sub_page); - -#elif defined(OS_IOS) - // iOS does not have a way to launch the date and time settings. - NOTREACHED(); - -#elif defined(OS_LINUX) - struct ClockCommand { - const char* pathname; - const char* argument; - }; - static const ClockCommand kClockCommands[] = { - // Unity - {"/usr/bin/unity-control-center", "datetime"}, - // GNOME - // - // NOTE: On old Ubuntu, naming control panels doesn't work, so it - // opens the overview. This will have to be good enough. - {"/usr/bin/gnome-control-center", "datetime"}, - {"/usr/local/bin/gnome-control-center", "datetime"}, - {"/opt/bin/gnome-control-center", "datetime"}, - // KDE - {"/usr/bin/kcmshell4", "clock"}, - {"/usr/local/bin/kcmshell4", "clock"}, - {"/opt/bin/kcmshell4", "clock"}, - }; - - base::CommandLine command(base::FilePath("")); - for (const ClockCommand& cmd : kClockCommands) { - base::FilePath pathname(cmd.pathname); - if (base::PathExists(pathname)) { - command.SetProgram(pathname); - command.AppendArg(cmd.argument); - break; - } - } - if (command.GetProgram().empty()) { - // Alas, there is nothing we can do. - return; - } - - base::LaunchOptions options; - options.wait = false; - options.allow_new_privs = true; - base::LaunchProcess(command, options); - -#elif defined(OS_MACOSX) - base::CommandLine command(base::FilePath("/usr/bin/open")); - command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane"); - - base::LaunchOptions options; - options.wait = false; - base::LaunchProcess(command, options); - -#elif defined(OS_WIN) - base::FilePath path; - PathService::Get(base::DIR_SYSTEM, &path); - static const base::char16 kControlPanelExe[] = L"control.exe"; - path = path.Append(base::string16(kControlPanelExe)); - base::CommandLine command(path); - command.AppendArg(std::string("/name")); - command.AppendArg(std::string("Microsoft.DateAndTime")); - - base::LaunchOptions options; - options.wait = false; - base::LaunchProcess(command, options); - -#else - NOTREACHED(); - -#endif - // Don't add code here! (See the comment at the beginning of the function.) -} - } // namespace // static @@ -186,24 +60,40 @@ callback_(callback), cert_error_(cert_error), ssl_info_(ssl_info), - time_triggered_(time_triggered) { + time_triggered_(time_triggered), + controller_(new ChromeControllerClient(web_contents)) { + // Get the language for the BadClockUI. + std::string languages; + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + if (profile) + languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages); + + // Set up the metrics helper for the BadClockUI. security_interstitials::MetricsHelper::ReportDetails reporting_info; reporting_info.metric_prefix = kMetricsName; - scoped_ptr<ChromeMetricsHelper> chrome_metrics_helper(new ChromeMetricsHelper( - web_contents, request_url, reporting_info, kMetricsName)); + ChromeMetricsHelper* chrome_metrics_helper = new ChromeMetricsHelper( + web_contents, request_url, reporting_info, kMetricsName); chrome_metrics_helper->StartRecordingCaptivePortalMetrics(false); - set_metrics_helper(chrome_metrics_helper.Pass()); - metrics_helper()->RecordUserInteraction( - security_interstitials::MetricsHelper::TOTAL_VISITS); + scoped_ptr<security_interstitials::MetricsHelper> metrics_helper( + chrome_metrics_helper); + controller_->set_metrics_helper(metrics_helper.Pass()); cert_report_helper_.reset(new CertReportHelper( ssl_cert_reporter.Pass(), web_contents, request_url, ssl_info, certificate_reporting::ErrorReport::INTERSTITIAL_CLOCK, - false /* overridable */, metrics_helper())); + false /* overridable */, controller_->metrics_helper())); - // TODO(felt): Separate the clock statistics from the main ssl statistics. - ssl_errors::RecordUMAStatistics(false, time_triggered_, request_url, - cert_error_, *ssl_info_.cert.get()); + bad_clock_ui_.reset(new security_interstitials::BadClockUI( + request_url, cert_error, ssl_info, time_triggered, languages, + controller_.get())); +} + +BadClockBlockingPage::~BadClockBlockingPage() { + if (!callback_.is_null()) { + // Deny when the page is closed. + NotifyDenyCertificate(); + } } bool BadClockBlockingPage::ShouldCreateNewNavigation() const { @@ -215,76 +105,13 @@ return BadClockBlockingPage::kTypeForTesting; } -BadClockBlockingPage::~BadClockBlockingPage() { - metrics_helper()->RecordShutdownMetrics(); - if (!callback_.is_null()) { - // Deny when the page is closed. - NotifyDenyCertificate(); - } +void BadClockBlockingPage::AfterShow() { + controller_->set_interstitial_page(interstitial_page()); } void BadClockBlockingPage::PopulateInterstitialStrings( base::DictionaryValue* load_time_data) { - CHECK(load_time_data); - base::string16 url(GetFormattedHostName()); - - // Values that are currently still shared with the SSL interstitial. - load_time_data->SetString("type", "SSL"); - load_time_data->SetString("errorCode", net::ErrorToString(cert_error_)); - load_time_data->SetString( - "openDetails", l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON)); - load_time_data->SetString( - "closeDetails", - l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON)); - - // Strings for the bad clock warning specifically. - load_time_data->SetBoolean("bad_clock", true); - load_time_data->SetBoolean("overridable", false); -#if defined(OS_IOS) - load_time_data->SetBoolean("hide_primary_button", true); -#else - load_time_data->SetBoolean("hide_primary_button", false); -#endif - - int heading_string = ssl_errors::IsUserClockInTheFuture(time_triggered_) - ? IDS_CLOCK_ERROR_AHEAD_HEADING - : IDS_CLOCK_ERROR_BEHIND_HEADING; - - load_time_data->SetString("tabTitle", - l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_TITLE)); - load_time_data->SetString("heading", - l10n_util::GetStringUTF16(heading_string)); - load_time_data->SetString( - "primaryParagraph", - l10n_util::GetStringFUTF16( - IDS_CLOCK_ERROR_PRIMARY_PARAGRAPH, url, - base::TimeFormatFriendlyDateAndTime(time_triggered_))); - - load_time_data->SetString( - "primaryButtonText", - l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_UPDATE_DATE_AND_TIME)); - load_time_data->SetString( - "explanationParagraph", - l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_EXPLANATION)); - - // The interstitial template expects this string, but we're not using it. - load_time_data->SetString("finalParagraph", std::string()); - - // Set debugging information at the bottom of the warning. - load_time_data->SetString("subject", - ssl_info_.cert->subject().GetDisplayName()); - load_time_data->SetString("issuer", - ssl_info_.cert->issuer().GetDisplayName()); - load_time_data->SetString( - "expirationDate", - base::TimeFormatShortDate(ssl_info_.cert->valid_expiry())); - load_time_data->SetString("currentDate", - base::TimeFormatShortDate(time_triggered_)); - std::vector<std::string> encoded_chain; - ssl_info_.cert->GetPEMEncodedChain(&encoded_chain); - load_time_data->SetString( - "pem", base::JoinString(encoded_chain, base::StringPiece())); - + bad_clock_ui_->PopulateStringsForHTML(load_time_data); cert_report_helper_->PopulateExtendedReportingOption(load_time_data); } @@ -315,7 +142,6 @@ } // This handles the commands sent from the interstitial JavaScript. -// DO NOT reorder or change this logic without also changing the JavaScript! void BadClockBlockingPage::CommandReceived(const std::string& command) { if (command == "\"pageLoadComplete\"") { // content::WaitForRenderFrameReady sends this message when the page @@ -326,36 +152,9 @@ int cmd = 0; bool retval = base::StringToInt(command, &cmd); DCHECK(retval); - switch (cmd) { - case security_interstitials::CMD_DONT_PROCEED: - interstitial_page()->DontProceed(); - break; - case security_interstitials::CMD_DO_REPORT: - SetReportingPreference(true); - break; - case security_interstitials::CMD_DONT_REPORT: - SetReportingPreference(false); - break; - case security_interstitials::CMD_SHOW_MORE_SECTION: - metrics_helper()->RecordUserInteraction( - security_interstitials::MetricsHelper::SHOW_ADVANCED); - break; - case security_interstitials::CMD_OPEN_DATE_SETTINGS: - metrics_helper()->RecordUserInteraction( - security_interstitials::MetricsHelper::OPEN_TIME_SETTINGS); - content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, - base::Bind(&LaunchDateAndTimeSettings)); - break; - case security_interstitials::CMD_OPEN_REPORTING_PRIVACY: - OpenExtendedReportingPrivacyPolicy(); - break; - case security_interstitials::CMD_PROCEED: - case security_interstitials::CMD_OPEN_HELP_CENTER: - case security_interstitials::CMD_RELOAD: - case security_interstitials::CMD_OPEN_DIAGNOSTIC: - // Not supported for the bad clock interstitial. - NOTREACHED() << "Unexpected command: " << command; - } + + bad_clock_ui_->HandleCommand( + static_cast<security_interstitials::SecurityInterstitialCommands>(cmd)); } void BadClockBlockingPage::OverrideRendererPrefs(
diff --git a/chrome/browser/ssl/bad_clock_blocking_page.h b/chrome/browser/ssl/bad_clock_blocking_page.h index 592dae86..c84079fe 100644 --- a/chrome/browser/ssl/bad_clock_blocking_page.h +++ b/chrome/browser/ssl/bad_clock_blocking_page.h
@@ -16,17 +16,22 @@ class CertReportHelper; class GURL; -// This class is responsible for showing/hiding the interstitial page that is -// shown when a certificate error happens. This error is not overridable. -// It deletes itself when the interstitial page is closed. +namespace security_interstitials { +class BadClockUI; +} + +// This class is responsible for showing/hiding the interstitial page that +// occurs when an SSL error is triggered by a clock misconfiguration. It +// creates the UI using security_interstitials::BadClockUI and then +// displays it. It deletes itself when the interstitial page is closed. class BadClockBlockingPage : public SecurityInterstitialPage { public: // Interstitial type, used in tests. static InterstitialPageDelegate::TypeID kTypeForTesting; - // Creates a bad clock interstitial. If the blocking page isn't shown, the - // caller is responsible for cleaning up the blocking page, otherwise the - // interstitial takes ownership when shown. + // If the blocking page isn't shown, the caller is responsible for cleaning + // up the blocking page. Otherwise, the interstitial takes ownership when + // shown. BadClockBlockingPage(content::WebContents* web_contents, int cert_error, const net::SSLInfo& ssl_info, @@ -44,7 +49,7 @@ scoped_ptr<SSLCertReporter> ssl_cert_reporter); protected: - // InterstitialPageDelegate implementation. + // InterstitialPageDelegate implementation: void CommandReceived(const std::string& command) override; void OverrideEntry(content::NavigationEntry* entry) override; void OverrideRendererPrefs(content::RendererPreferences* prefs) override; @@ -54,6 +59,7 @@ bool ShouldCreateNewNavigation() const override; void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) override; + void AfterShow() override; private: void NotifyDenyCertificate(); @@ -61,11 +67,10 @@ base::Callback<void(bool)> callback_; const int cert_error_; const net::SSLInfo ssl_info_; - - // The time at which the interstitial was triggered. The interstitial - // calculates all times relative to this. const base::Time time_triggered_; + scoped_ptr<ChromeControllerClient> controller_; + scoped_ptr<security_interstitials::BadClockUI> bad_clock_ui_; scoped_ptr<CertReportHelper> cert_report_helper_; DISALLOW_COPY_AND_ASSIGN(BadClockBlockingPage);
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.h b/chrome/browser/ssl/captive_portal_blocking_page.h index 613bcf30..ec7e0cb 100644 --- a/chrome/browser/ssl/captive_portal_blocking_page.h +++ b/chrome/browser/ssl/captive_portal_blocking_page.h
@@ -61,6 +61,7 @@ bool ShouldCreateNewNavigation() const override; void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) override; + void AfterShow() override {} // InterstitialPageDelegate method: void CommandReceived(const std::string& command) override;
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h index 5387c81..9e1c82a 100644 --- a/chrome/browser/ssl/ssl_blocking_page.h +++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -94,6 +94,7 @@ bool ShouldCreateNewNavigation() const override; void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) override; + void AfterShow() override {} private: void NotifyDenyCertificate();
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc index 9788f238..5b69f26b 100644 --- a/chrome/browser/sync/profile_sync_service_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -685,6 +685,30 @@ EXPECT_TRUE(service()->GetAccessTokenForTest().empty()); } +// CrOS does not support signout. +#if !defined(OS_CHROMEOS) +TEST_F(ProfileSyncServiceTest, SignOutRevokeAccessToken) { + CreateService(browser_sync::AUTO_START); + IssueTestTokens(); + ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback()); + ExpectSyncBackendHostCreation(1); + InitializeForNthSync(); + EXPECT_TRUE(service()->IsSyncActive()); + + std::string primary_account_id = + SigninManagerFactory::GetForProfile(profile()) + ->GetAuthenticatedAccountId(); + ProfileOAuth2TokenServiceFactory::GetForProfile(profile()) + ->LoadCredentials(primary_account_id); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(service()->GetAccessTokenForTest().empty()); + + SigninManagerFactory::GetForProfile(profile()) + ->SignOut(signin_metrics::SIGNOUT_TEST); + EXPECT_TRUE(service()->GetAccessTokenForTest().empty()); +} +#endif + #if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP) TEST_F(ProfileSyncServiceTest, DontStartBackupOnBrowserStart) { CreateServiceWithoutSignIn();
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index 0b5efdb..5a9b48f 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/files/scoped_temp_dir.h" #include "base/guid.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -309,6 +310,33 @@ return entry->GetHttpStatusCode() == 200; } +void SyncTest::CreateProfile(int index) { + tmp_profile_paths_[index] = new base::ScopedTempDir(); + if (UsingExternalServers() && num_clients_ > 1) { + // For multi profile UI signin, profile paths should be outside user data + // dir to allow signing-in multiple profiles to same account. Otherwise, we + // get an error that the profile has already signed in on this device. + CHECK(tmp_profile_paths_[index]->CreateUniqueTempDir()); + } else { + // Create new profiles in user data dir so that other profiles can know + // about it. This is needed in tests such as supervised user cases which + // assume browser->profile() as the custodian profile. + base::FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + CHECK( + tmp_profile_paths_[index]->CreateUniqueTempDirUnderPath(user_data_dir)); + } + base::FilePath profile_path = tmp_profile_paths_[index]->path(); + if (UsingExternalServers()) { + // If running against an EXTERNAL_LIVE_SERVER, we signin profiles using real + // GAIA server. This requires creating profiles with no test hooks. + profiles_[index] = MakeProfileForUISignin(profile_path); + } else { + // Without need of real GAIA authentication, we create new test profiles. + profiles_[index] = MakeTestProfile(profile_path); + } +} + // Called when the ProfileManager has created a profile. // static void SyncTest::CreateProfileCallback(const base::Closure& quit_closure, @@ -329,22 +357,7 @@ // UI signin we need profiles in unique user data dir's and we need to use // ProfileManager::CreateProfileAsync() for proper profile creation. // static -Profile* SyncTest::MakeProfileForUISignin( - const base::FilePath::StringType name, - bool path_outside_user_data_dir) { - // For multi profile UI signin, profile paths should be outside user data dir. - // Otherwise, we get an error that the profile has already signed in on this - // device. - // Note that prefix |name| is implemented only on Win. On other platforms the - // com.google.Chrome.XXXXXX prefix is used. - base::FilePath profile_path; - if (path_outside_user_data_dir) { - CHECK(base::CreateNewTempDirectory(name, &profile_path)); - } else { - PathService::Get(chrome::DIR_USER_DATA, &profile_path); - profile_path = profile_path.Append(name); - } - +Profile* SyncTest::MakeProfileForUISignin(base::FilePath profile_path) { ProfileManager* profile_manager = g_browser_process->profile_manager(); base::RunLoop run_loop; ProfileManager::CreateCallback create_callback = base::Bind( @@ -358,28 +371,18 @@ return profile_manager->GetProfileByPath(profile_path); } -Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) { - base::FilePath path; - // Create new profiles in user data dir so that other profiles can know about - // it. This is needed in tests such as supervised user cases which assume - // browser->profile() as the custodian profile. - PathService::Get(chrome::DIR_USER_DATA, &path); - path = path.Append(name); - - if (!base::PathExists(path)) - CHECK(base::CreateDirectory(path)); - +Profile* SyncTest::MakeTestProfile(base::FilePath profile_path) { if (!preexisting_preferences_file_contents_.empty()) { - base::FilePath pref_path(path.Append(chrome::kPreferencesFilename)); + base::FilePath pref_path(profile_path.Append(chrome::kPreferencesFilename)); const char* contents = preexisting_preferences_file_contents_.c_str(); size_t contents_length = preexisting_preferences_file_contents_.size(); if (!base::WriteFile(pref_path, contents, contents_length)) { LOG(FATAL) << "Preexisting Preferences file could not be written."; } } - - Profile* profile = - Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS); + Profile* profile = Profile::CreateProfile(profile_path, + NULL, + Profile::CREATE_MODE_SYNCHRONOUS); g_browser_process->profile_manager()->RegisterTestingProfile(profile, true, true); @@ -442,6 +445,7 @@ // Create the required number of sync profiles, browsers and clients. profiles_.resize(num_clients_); + tmp_profile_paths_.resize(num_clients_); browsers_.resize(num_clients_); clients_.resize(num_clients_); invalidation_forwarders_.resize(num_clients_); @@ -457,7 +461,10 @@ // Create the verifier profile. if (use_verifier_) { - verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier")); + base::FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + verifier_ = MakeTestProfile( + user_data_dir.Append(FILE_PATH_LITERAL("Verifier"))); bookmarks::test::WaitForBookmarkModelToLoad( BookmarkModelFactory::GetForProfile(verifier())); ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( @@ -472,19 +479,7 @@ } void SyncTest::InitializeInstance(int index) { - base::FilePath::StringType profile_name = - base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index); - // If running against an EXTERNAL_LIVE_SERVER, we need to signin profiles - // using real GAIA server. This requires creating profiles with no test hooks. - if (UsingExternalServers()) { - bool path_outside_user_data_dir = (num_clients_ > 1); - profiles_[index] = - MakeProfileForUISignin(profile_name, path_outside_user_data_dir); - } else { - // Without need of real GAIA authentication, we create new test profiles. - profiles_[index] = MakeProfile(profile_name); - } - + CreateProfile(index); EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile " << index << ".";
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index 76765b3..969a2e47 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -46,6 +46,7 @@ namespace base { class CommandLine; +class ScopedTempDir; } namespace fake_server { @@ -287,14 +288,15 @@ scoped_ptr<fake_server::FakeServer> fake_server_; private: - // Helper to ProfileManager::CreateProfileAsync that creates a new profile - // used for UI Signin. Blocks until profile is created. If - // |path_outside_user_data_dir| is true then profile's path is created outside - // user data dir which allows signing-in multiple profiles to same account. - static Profile* MakeProfileForUISignin(const base::FilePath::StringType name, - bool path_outside_user_data_dir); + // Handles Profile creation for given index. Profile's path and type is + // determined at runtime based on server type. + void CreateProfile(int index); - // Callback for CreateNewProfile() method. It runs the quit_closure once + // Helper to ProfileManager::CreateProfileAsync that creates a new profile + // used for UI Signin. Blocks until profile is created. + static Profile* MakeProfileForUISignin(base::FilePath profile_path); + + // Callback for MakeProfileForUISignin() method. It runs the quit_closure once // profile is created successfully. static void CreateProfileCallback(const base::Closure& quit_closure, Profile* profile, @@ -302,7 +304,7 @@ // Helper to Profile::CreateProfile that handles path creation. It creates // a profile then registers it as a testing profile. - Profile* MakeProfile(const base::FilePath::StringType name); + Profile* MakeTestProfile(base::FilePath profile_path); // Helper method used to create a Gaia account at runtime. // This function should only be called when running against external servers @@ -388,6 +390,11 @@ // directory. Profiles are owned by the ProfileManager. std::vector<Profile*> profiles_; + // Collection of profile paths used by a test. Each profile has a unique path + // which should be cleaned up at test shutdown. Profile paths inside the + // default user data dir gets deleted at InProcessBrowserTest teardown. + std::vector<base::ScopedTempDir*> tmp_profile_paths_; + // Collection of pointers to the browser objects used by a test. One browser // instance is created for each sync profile. Browser object lifetime is // managed by BrowserList, so we don't use a ScopedVector here.
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc index 13cc2c14..c2cd8ca 100644 --- a/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc +++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc
@@ -7,6 +7,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/test/sequenced_worker_pool_owner.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/sync_file_system/drive_backend/callback_helper.h" #include "chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h" @@ -28,7 +29,7 @@ public: typedef RemoteFileSyncService::OriginStatusMap RemoteOriginStatusMap; - SyncEngineTest() {} + SyncEngineTest() : worker_pool_owner_(1, "Worker") {} ~SyncEngineTest() override {} void SetUp() override { @@ -37,28 +38,25 @@ scoped_ptr<drive::DriveServiceInterface> fake_drive_service(new drive::FakeDriveService); - worker_pool_ = new base::SequencedWorkerPool(1, "Worker"); scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = base::ThreadTaskRunnerHandle::Get(); worker_task_runner_ = - worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool_->GetSequenceToken(), + worker_pool_owner_.pool()->GetSequencedTaskRunnerWithShutdownBehavior( + worker_pool_owner_.pool()->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); sync_engine_.reset(new drive_backend::SyncEngine( - ui_task_runner.get(), - worker_task_runner_.get(), - nullptr /* drive_task_runner */, - worker_pool_.get(), - profile_dir_.path(), - nullptr /* task_logger */, - nullptr /* notification_manager */, - nullptr /* extension_service */, - nullptr /* signin_manager */, - nullptr /* token_service */, - nullptr /* request_context */, - nullptr /* drive_service_factory */, - nullptr /* in_memory_env */)); + ui_task_runner.get(), worker_task_runner_.get(), + nullptr, // drive_task_runner + worker_pool_owner_.pool().get(), profile_dir_.path(), + nullptr, // task_logger + nullptr, // notification_manager + nullptr, // extension_service + nullptr, // signin_manager + nullptr, // token_service + nullptr, // request_context + nullptr, // drive_service_factory + nullptr)); // in_memory_env sync_engine_->InitializeForTesting( fake_drive_service.Pass(), @@ -73,12 +71,8 @@ void TearDown() override { sync_engine_.reset(); WaitForWorkerTaskRunner(); - worker_pool_->Shutdown(); worker_task_runner_ = nullptr; - worker_pool_ = nullptr; - - base::RunLoop().RunUntilIdle(); } bool FindOriginStatus(const GURL& origin, std::string* status) { @@ -131,7 +125,7 @@ base::ScopedTempDir profile_dir_; scoped_ptr<drive_backend::SyncEngine> sync_engine_; - scoped_refptr<base::SequencedWorkerPool> worker_pool_; + base::SequencedWorkerPoolOwner worker_pool_owner_; scoped_refptr<base::SequencedTaskRunner> worker_task_runner_; DISALLOW_COPY_AND_ASSIGN(SyncEngineTest);
diff --git a/chrome/browser/ui/app_list/search/history_unittest.cc b/chrome/browser/ui/app_list/search/history_unittest.cc index d5365e6..41578f1 100644 --- a/chrome/browser/ui/app_list/search/history_unittest.cc +++ b/chrome/browser/ui/app_list/search/history_unittest.cc
@@ -99,7 +99,6 @@ } void TearDown() override { Flush(); - worker_pool_owner_->pool()->Shutdown(); } void CreateHistory() {
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index de571bcc..5857df7 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -45,6 +45,8 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_ui_prefs.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" @@ -3211,7 +3213,7 @@ auto app_contents = app_browser->tab_strip_model()->GetActiveWebContents(); CheckDisplayModeMQ(ASCIIToUTF16("standalone"), app_contents); - app_browser->window()->EnterFullscreen( + app_browser->exclusive_access_manager()->context()->EnterFullscreen( GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION, false);
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index b334c083..668a98c8 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -132,17 +132,6 @@ // + or - in the wrench menu to change zoom). virtual void ZoomChangedForActiveTab(bool can_show_bubble) = 0; - // Methods that change fullscreen state. - // On Mac, the tab strip and toolbar will be shown if |with_toolbar| is true, - // |with_toolbar| is ignored on other platforms. - virtual void EnterFullscreen(const GURL& url, - ExclusiveAccessBubbleType bubble_type, - bool with_toolbar) = 0; - virtual void ExitFullscreen() = 0; - virtual void UpdateExclusiveAccessExitBubbleContent( - const GURL& url, - ExclusiveAccessBubbleType bubble_type) = 0; - // Windows and GTK remove the top controls in fullscreen, but Mac and Ash // keep the controls in a slide-down panel. virtual bool ShouldHideUIForFullscreen() const = 0;
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm index e0874c64..022b334 100644 --- a/chrome/browser/ui/cocoa/applescript/window_applescript.mm +++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -22,6 +22,8 @@ #include "chrome/browser/ui/cocoa/applescript/error_applescript.h" #include "chrome/browser/ui/cocoa/applescript/metrics_applescript.h" #import "chrome/browser/ui/cocoa/applescript/tab_applescript.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -266,18 +268,14 @@ - (void)handlesEnterPresentationMode:(NSScriptCommand*)command { AppleScript::LogAppleScriptUMA( AppleScript::AppleScriptCommand::WINDOW_ENTER_PRESENTATION_MODE); - if (browser_->window()) { - browser_->window()->EnterFullscreen( - GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION, - false); - } + browser_->exclusive_access_manager()->context()->EnterFullscreen( + GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION, false); } - (void)handlesExitPresentationMode:(NSScriptCommand*)command { AppleScript::LogAppleScriptUMA( AppleScript::AppleScriptCommand::WINDOW_EXIT_PRESENTATION_MODE); - if (browser_->window()) - browser_->window()->ExitFullscreen(); + browser_->exclusive_access_manager()->context()->ExitFullscreen(); } @end
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm index 8a51d8a5..c775514 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm
@@ -431,7 +431,9 @@ // Test adding an extension while the app menu is open. Regression test for // crbug.com/561237. -IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, AddExtensionWithMenuOpen) { +// Flaky: http://crbug.com/564623 +IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, + DISABLED_AddExtensionWithMenuOpen) { // Add an extension to ensure the overflow menu is present. scoped_refptr<const extensions::Extension> extension = extensions::extension_action_test_util::CreateActionExtension(
diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm index 5d99c136..24cc6c21 100644 --- a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm +++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
@@ -14,6 +14,8 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/cocoa/view_id_util.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" +#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/bookmarks/browser/bookmark_model.h" @@ -97,7 +99,7 @@ // Flaky on Mac: http://crbug.com/90557. IN_PROC_BROWSER_TEST_F(ViewIDTest, DISABLED_Fullscreen) { - browser()->window()->EnterFullscreen( + browser()->exclusive_access_manager()->context()->EnterFullscreen( GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION, false); ASSERT_NO_FATAL_FAILURE(DoTest());
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc index 5fd817a..a8970fd 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
@@ -41,10 +41,6 @@ ~FullscreenControllerTestWindow() override {} // BrowserWindow Interface: - void EnterFullscreen(const GURL& url, - ExclusiveAccessBubbleType type, - bool with_toolbar) override; - void ExitFullscreen() override; bool ShouldHideUIForFullscreen() const override; bool IsFullscreen() const override; bool SupportsFullscreenWithToolbar() const override; @@ -64,6 +60,10 @@ content::WebContents* GetActiveWebContents() override; void HideDownloadShelf() override; void UnhideDownloadShelf() override; + void EnterFullscreen(const GURL& url, + ExclusiveAccessBubbleType type, + bool with_toolbar) override; + void ExitFullscreen() override; void UpdateExclusiveAccessExitBubbleContent( const GURL& url, ExclusiveAccessBubbleType bubble_type) override; @@ -240,9 +240,7 @@ void FullscreenControllerTestWindow::UpdateExclusiveAccessExitBubbleContent( const GURL& url, - ExclusiveAccessBubbleType bubble_type) { - TestBrowserWindow::UpdateExclusiveAccessExitBubbleContent(url, bubble_type); -} + ExclusiveAccessBubbleType bubble_type) {} // FullscreenControllerStateUnitTest ------------------------------------------- @@ -453,16 +451,16 @@ } // Test that the fullscreen exit bubble is closed by -// WindowFullscreenStateChanged() if fullscreen is exited via BrowserWindow. -// This currently occurs when an extension exits fullscreen via changing the -// browser bounds. -TEST_F(FullscreenControllerStateUnitTest, ExitFullscreenViaBrowserWindow) { +// WindowFullscreenStateChanged() if fullscreen is exited via the +// ExclusiveAccessContext interface. +TEST_F(FullscreenControllerStateUnitTest, + ExitFullscreenViaExclusiveAccessContext) { AddTab(browser(), GURL(url::kAboutBlankURL)); ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN)); ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)); ASSERT_TRUE(browser()->window()->IsFullscreen()); // Exit fullscreen without going through fullscreen controller. - browser()->window()->ExitFullscreen(); + window_->ExitFullscreen(); ChangeWindowFullscreenState(); EXPECT_EQ(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE, browser()
diff --git a/chrome/browser/ui/views/DEPS b/chrome/browser/ui/views/DEPS index 3f474c4500..9f12b1bf 100644 --- a/chrome/browser/ui/views/DEPS +++ b/chrome/browser/ui/views/DEPS
@@ -3,5 +3,6 @@ "+content/app/resources/grit/content_resources.h", "+chrome/browser/ui/views", "+components/constrained_window", + "+components/mus/public/cpp", "+components/user_manager", ]
diff --git a/chrome/browser/ui/views/frame/browser_frame_mus.cc b/chrome/browser/ui/views/frame/browser_frame_mus.cc index e429361..6177d1a1 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mus.cc +++ b/chrome/browser/ui/views/frame/browser_frame_mus.cc
@@ -5,20 +5,32 @@ #include "chrome/browser/ui/views/frame/browser_frame_mus.h" #include "chrome/browser/ui/views/frame/browser_frame.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "components/mus/public/cpp/window.h" #include "components/mus/public/interfaces/window_tree.mojom.h" #include "mojo/application/public/cpp/application_impl.h" #include "ui/views/mus/window_manager_connection.h" +#include "ui/views/mus/window_manager_frame_values.h" + +namespace { + +mus::Window* CreateMusWindow(BrowserView* browser_view) { + std::map<std::string, std::vector<uint8_t>> properties; + views::NativeWidgetMus::ConfigurePropertiesForNewWindowFromDelegate( + browser_view, &properties); + return views::WindowManagerConnection::Get()->NewWindow(properties); +} + +} // namespace BrowserFrameMus::BrowserFrameMus(BrowserFrame* browser_frame, BrowserView* browser_view) : views::NativeWidgetMus( browser_frame, views::WindowManagerConnection::Get()->app()->shell(), - views::WindowManagerConnection::Get()->NewWindow( - std::map<std::string, std::vector<uint8_t>>()), + CreateMusWindow(browser_view), mus::mojom::SURFACE_TYPE_DEFAULT), - browser_view_(browser_view) { -} + browser_view_(browser_view) {} BrowserFrameMus::~BrowserFrameMus() {} @@ -50,3 +62,8 @@ int BrowserFrameMus::GetMinimizeButtonOffset() const { return 0; } + +void BrowserFrameMus::UpdateClientArea() { + window()->SetClientArea( + views::WindowManagerFrameValues::instance().normal_insets); +}
diff --git a/chrome/browser/ui/views/frame/browser_frame_mus.h b/chrome/browser/ui/views/frame/browser_frame_mus.h index e120aba..db389bc9 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mus.h +++ b/chrome/browser/ui/views/frame/browser_frame_mus.h
@@ -25,6 +25,9 @@ ui::WindowShowState* show_state) const override; int GetMinimizeButtonOffset() const override; + // Overriden from NativeWidgetMus: + void UpdateClientArea() override; + BrowserView* browser_view_; DISALLOW_COPY_AND_ASSIGN(BrowserFrameMus);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc index c7ae34f0..7ee9c48e 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_ash.cc
@@ -6,6 +6,11 @@ #include "chrome/browser/ui/views/frame/browser_view.h" +#if defined(MOJO_SHELL_CLIENT) +#include "chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h" +#include "content/public/common/mojo_shell_connection.h" +#endif + #if !defined(OS_CHROMEOS) #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h" #endif @@ -19,6 +24,15 @@ BrowserNonClientFrameView* CreateBrowserNonClientFrameView( BrowserFrame* frame, BrowserView* browser_view) { +#if defined(MOJO_SHELL_CLIENT) + if (content::MojoShellConnection::Get()) { + BrowserNonClientFrameViewMus* frame_view = + new BrowserNonClientFrameViewMus(frame, browser_view); + frame_view->Init(); + return frame_view; + } +#endif + #if !defined(OS_CHROMEOS) if (browser_view->browser()->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc new file mode 100644 index 0000000..bac7c90 --- /dev/null +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc
@@ -0,0 +1,610 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h" + +#include <algorithm> + +#include "base/profiler/scoped_tracker.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/extensions/extension_util.h" +#include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/themes/theme_properties.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/views/frame/browser_frame.h" +#include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/frame/immersive_mode_controller.h" +#include "chrome/browser/ui/views/frame/web_app_left_header_view_ash.h" +#include "chrome/browser/ui/views/layout_constants.h" +#include "chrome/browser/ui/views/profiles/avatar_menu_button.h" +#include "chrome/browser/ui/views/tab_icon_view.h" +#include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/browser/web_applications/web_app.h" +#include "components/signin/core/common/profile_management_switches.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/extension_registry.h" +#include "grit/theme_resources.h" +#include "ui/accessibility/ax_view_state.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" +#include "ui/base/hit_test.h" +#include "ui/base/layout.h" +#include "ui/base/resource/material_design/material_design_controller.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/theme_provider.h" +#include "ui/compositor/layer_animator.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/layout_constants.h" +#include "ui/views/mus/window_manager_frame_values.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +#if defined(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" +#endif + +namespace { + +#if defined(FRAME_AVATAR_BUTTON) +// Space between the new avatar button and the minimize button. +const int kNewAvatarButtonOffset = 5; +#endif +// Space between right edge of tabstrip and maximize button. +const int kTabstripRightSpacing = 10; +// Height of the shadow of the content area, at the top of the toolbar. +const int kContentShadowHeight = 1; +// Space between top of window and top of tabstrip for tall headers, such as +// for restored windows, apps, etc. +const int kTabstripTopSpacingTall = 4; +// Space between top of window and top of tabstrip for short headers, such as +// for maximized windows, pop-ups, etc. +const int kTabstripTopSpacingShort = 0; +// Height of the shadow in the tab image, used to ensure clicks in the shadow +// area still drag restored windows. This keeps the clickable area large enough +// to hit easily. +const int kTabShadowHeight = 4; + +// Combines View::ConvertPointToTarget() and View::HitTest() for a given +// |point|. Converts |point| from |src| to |dst| and hit tests it against |dst|. +bool ConvertedHitTest(views::View* src, + views::View* dst, + const gfx::Point& point) { + DCHECK(src); + DCHECK(dst); + gfx::Point converted_point(point); + views::View::ConvertPointToTarget(src, dst, &converted_point); + return dst->HitTestPoint(converted_point); +} + +const views::WindowManagerFrameValues& frame_values() { + return views::WindowManagerFrameValues::instance(); +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// BrowserNonClientFrameViewMus, public: + +// static +const char BrowserNonClientFrameViewMus::kViewClassName[] = + "BrowserNonClientFrameViewMus"; + +BrowserNonClientFrameViewMus::BrowserNonClientFrameViewMus( + BrowserFrame* frame, + BrowserView* browser_view) + : BrowserNonClientFrameView(frame, browser_view), + web_app_left_header_view_(nullptr), + window_icon_(nullptr) {} + +BrowserNonClientFrameViewMus::~BrowserNonClientFrameViewMus() {} + +void BrowserNonClientFrameViewMus::Init() { + // Initializing the TabIconView is expensive, so only do it if we need to. + if (browser_view()->ShouldShowWindowIcon()) { + window_icon_ = new TabIconView(this, nullptr); + window_icon_->set_is_light(true); + AddChildView(window_icon_); + window_icon_->Update(); + } + + UpdateAvatar(); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserNonClientFrameView: + +gfx::Rect BrowserNonClientFrameViewMus::GetBoundsForTabStrip( + views::View* tabstrip) const { + if (!tabstrip) + return gfx::Rect(); + + // When the tab strip is painted in the immersive fullscreen light bar style, + // the caption buttons and the avatar button are not visible. However, their + // bounds are still used to compute the tab strip bounds so that the tabs have + // the same horizontal position when the tab strip is painted in the immersive + // light bar style as when the top-of-window views are revealed. + int left_inset = GetTabStripLeftInset(); + int right_inset = GetTabStripRightInset(); + return gfx::Rect(left_inset, GetTopInset(false), + std::max(0, width() - left_inset - right_inset), + tabstrip->GetPreferredSize().height()); +} + +int BrowserNonClientFrameViewMus::GetTopInset(bool restored) const { + if (!ShouldPaint() || UseImmersiveLightbarHeaderStyle()) + return 0; + + if (browser_view()->IsTabStripVisible()) { + return ((frame()->IsMaximized() || frame()->IsFullscreen()) && !restored) + ? kTabstripTopSpacingShort + : kTabstripTopSpacingTall; + } + + int caption_buttons_bottom = frame_values().normal_insets.top(); + + // The toolbar partially overlaps the caption buttons. + if (browser_view()->IsToolbarVisible()) + return caption_buttons_bottom - kContentShadowHeight; + + return caption_buttons_bottom + kClientEdgeThickness; +} + +int BrowserNonClientFrameViewMus::GetThemeBackgroundXInset() const { + return 5; +} + +void BrowserNonClientFrameViewMus::UpdateThrobber(bool running) { + if (window_icon_) + window_icon_->Update(); +} + +void BrowserNonClientFrameViewMus::UpdateToolbar() { + if (web_app_left_header_view_) + web_app_left_header_view_->Update(); +} + +views::View* BrowserNonClientFrameViewMus::GetLocationIconView() const { + if (web_app_left_header_view_) + return web_app_left_header_view_->GetLocationIconView(); + + return nullptr; +} + +/////////////////////////////////////////////////////////////////////////////// +// views::NonClientFrameView: + +gfx::Rect BrowserNonClientFrameViewMus::GetBoundsForClientView() const { + // The ClientView must be flush with the top edge of the widget so that the + // web contents can take up the entire screen in immersive fullscreen (with + // or without the top-of-window views revealed). When in immersive fullscreen + // and the top-of-window views are revealed, the TopContainerView paints the + // window header by redirecting paints from its background to + // BrowserNonClientFrameViewMus. + return bounds(); +} + +gfx::Rect BrowserNonClientFrameViewMus::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + return client_bounds; +} + +int BrowserNonClientFrameViewMus::NonClientHitTest(const gfx::Point& point) { + // TODO(sky): figure out how this interaction should work. + int hit_test = HTCLIENT; + +#if defined(FRAME_AVATAR_BUTTON) + if (hit_test == HTCAPTION && new_avatar_button() && + ConvertedHitTest(this, new_avatar_button(), point)) { + return HTCLIENT; + } +#endif + + // See if the point is actually within the web app back button. + if (hit_test == HTCAPTION && web_app_left_header_view_ && + ConvertedHitTest(this, web_app_left_header_view_, point)) { + return HTCLIENT; + } + +#if defined(ENABLE_SUPERVISED_USERS) + // ...or within the avatar label, if it's a supervised user. + if (hit_test == HTCAPTION && supervised_user_avatar_label() && + ConvertedHitTest(this, supervised_user_avatar_label(), point)) { + return HTCLIENT; + } +#endif + + // When the window is restored we want a large click target above the tabs + // to drag the window, so redirect clicks in the tab's shadow to caption. + if (hit_test == HTCLIENT && + !(frame()->IsMaximized() || frame()->IsFullscreen())) { + // Convert point to client coordinates. + gfx::Point client_point(point); + View::ConvertPointToTarget(this, frame()->client_view(), &client_point); + // Report hits in shadow at top of tabstrip as caption. + gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds()); + if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight) + hit_test = HTCAPTION; + } + return hit_test; +} + +void BrowserNonClientFrameViewMus::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + // Aura does not use window masks. +} + +void BrowserNonClientFrameViewMus::ResetWindowControls() {} + +void BrowserNonClientFrameViewMus::UpdateWindowIcon() { + if (window_icon_) + window_icon_->SchedulePaint(); +} + +void BrowserNonClientFrameViewMus::UpdateWindowTitle() {} + +void BrowserNonClientFrameViewMus::SizeConstraintsChanged() {} + +/////////////////////////////////////////////////////////////////////////////// +// views::View: + +void BrowserNonClientFrameViewMus::OnPaint(gfx::Canvas* canvas) { + if (!ShouldPaint()) + return; + + // TODO(sky): get immersive mode working. + + if (UseImmersiveLightbarHeaderStyle()) { + PaintImmersiveLightbarStyleHeader(canvas); + return; + } + + if (web_app_left_header_view_) + web_app_left_header_view_->SetPaintAsActive(ShouldPaintAsActive()); + + if (browser_view()->IsToolbarVisible()) + PaintToolbarBackground(canvas); + else if (!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle()) + PaintContentEdge(canvas); +} + +void BrowserNonClientFrameViewMus::Layout() { + if (avatar_button()) + LayoutAvatar(); + +#if defined(FRAME_AVATAR_BUTTON) + if (new_avatar_button()) + LayoutNewStyleAvatar(); +#endif + + BrowserNonClientFrameView::Layout(); +} + +const char* BrowserNonClientFrameViewMus::GetClassName() const { + return kViewClassName; +} + +void BrowserNonClientFrameViewMus::GetAccessibleState(ui::AXViewState* state) { + state->role = ui::AX_ROLE_TITLE_BAR; +} + +gfx::Size BrowserNonClientFrameViewMus::GetMinimumSize() const { + gfx::Size min_client_view_size(frame()->client_view()->GetMinimumSize()); + const int min_frame_width = frame_values().max_title_bar_button_width + + frame_values().normal_insets.width(); + int min_width = std::max(min_frame_width, min_client_view_size.width()); + if (browser_view()->IsTabStripVisible()) { + // Ensure that the minimum width is enough to hold a minimum width tab strip + // at its usual insets. + int min_tabstrip_width = + browser_view()->tabstrip()->GetMinimumSize().width(); + min_width = + std::max(min_width, min_tabstrip_width + GetTabStripLeftInset() + + GetTabStripRightInset()); + } + return gfx::Size(min_width, min_client_view_size.height()); +} + +void BrowserNonClientFrameViewMus::ChildPreferredSizeChanged( + views::View* child) { + // FrameCaptionButtonContainerView animates the visibility changes in + // UpdateSizeButtonVisibility(false). Due to this a new size is not available + // until the completion of the animation. Layout in response to the preferred + // size changes. + if (!browser_view()->initialized()) + return; + bool needs_layout = false; +#if defined(FRAME_AVATAR_BUTTON) + needs_layout = needs_layout || child == new_avatar_button(); +#endif + if (needs_layout) { + InvalidateLayout(); + frame()->GetRootView()->Layout(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// TabIconViewModel: + +bool BrowserNonClientFrameViewMus::ShouldTabIconViewAnimate() const { + // This function is queried during the creation of the window as the + // TabIconView we host is initialized, so we need to null check the selected + // WebContents because in this condition there is not yet a selected tab. + content::WebContents* current_tab = browser_view()->GetActiveWebContents(); + return current_tab ? current_tab->IsLoading() : false; +} + +gfx::ImageSkia BrowserNonClientFrameViewMus::GetFaviconForTabIconView() { + views::WidgetDelegate* delegate = frame()->widget_delegate(); + if (!delegate) + return gfx::ImageSkia(); + return delegate->GetWindowIcon(); +} + +/////////////////////////////////////////////////////////////////////////////// +// views::ButtonListener: + +void BrowserNonClientFrameViewMus::ButtonPressed(views::Button* sender, + const ui::Event& event) { +#if !defined(FRAME_AVATAR_BUTTON) + NOTREACHED(); +#else + DCHECK(sender == new_avatar_button()); + int command = IDC_SHOW_AVATAR_MENU; + if (event.IsMouseEvent() && + static_cast<const ui::MouseEvent&>(event).IsRightMouseButton()) { + command = IDC_SHOW_FAST_USER_SWITCHER; + } + chrome::ExecuteCommand(browser_view()->browser(), command); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserNonClientFrameViewMus, protected: + +// BrowserNonClientFrameView: +void BrowserNonClientFrameViewMus::UpdateNewAvatarButtonImpl() { +#if defined(FRAME_AVATAR_BUTTON) + UpdateNewAvatarButton(this, NewAvatarButton::NATIVE_BUTTON); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserNonClientFrameViewMus, private: + +// views::NonClientFrameView: +bool BrowserNonClientFrameViewMus::DoesIntersectRect( + const views::View* target, + const gfx::Rect& rect) const { + CHECK_EQ(target, this); + if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect)) { + // |rect| is outside BrowserNonClientFrameViewMus's bounds. + return false; + } + + TabStrip* tabstrip = browser_view()->tabstrip(); + if (tabstrip && browser_view()->IsTabStripVisible()) { + // Claim |rect| only if it is above the bottom of the tabstrip in a non-tab + // portion. + gfx::RectF rect_in_tabstrip_coords_f(rect); + View::ConvertRectToTarget(this, tabstrip, &rect_in_tabstrip_coords_f); + gfx::Rect rect_in_tabstrip_coords = + gfx::ToEnclosingRect(rect_in_tabstrip_coords_f); + + if (rect_in_tabstrip_coords.y() > tabstrip->height()) + return false; + + return !tabstrip->HitTestRect(rect_in_tabstrip_coords) || + tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords); + } + + // Claim |rect| if it is above the top of the topmost view in the client area. + return rect.y() < GetTopInset(false); +} + +int BrowserNonClientFrameViewMus::GetTabStripLeftInset() const { + const gfx::Insets insets(GetLayoutInsets(AVATAR_ICON)); + const int avatar_right = + avatar_button() + ? (insets.left() + browser_view()->GetOTRAvatarIcon().width()) + : 0; + return avatar_right + insets.right() + frame_values().normal_insets.left(); +} + +int BrowserNonClientFrameViewMus::GetTabStripRightInset() const { + const int frame_right_insets = frame_values().normal_insets.right() + + frame_values().max_title_bar_button_width; + int right_inset = kTabstripRightSpacing + frame_right_insets; + +#if defined(FRAME_AVATAR_BUTTON) + if (new_avatar_button()) { + right_inset += kNewAvatarButtonOffset + + new_avatar_button()->GetPreferredSize().width(); + } +#endif + + return right_inset; +} + +bool BrowserNonClientFrameViewMus::UseImmersiveLightbarHeaderStyle() const { + ImmersiveModeController* immersive_controller = + browser_view()->immersive_mode_controller(); + return immersive_controller->IsEnabled() && + !immersive_controller->IsRevealed() && + browser_view()->IsTabStripVisible(); +} + +bool BrowserNonClientFrameViewMus::UsePackagedAppHeaderStyle() const { + Browser* browser = browser_view()->browser(); + // For non tabbed trusted source windows, e.g. Settings, use the packaged + // app style frame. + if (!browser->is_type_tabbed() && browser->is_trusted_source()) + return true; + // Use the packaged app style for apps that aren't using the newer WebApp + // style. + return browser->is_app() && !UseWebAppHeaderStyle(); +} + +bool BrowserNonClientFrameViewMus::UseWebAppHeaderStyle() const { + return browser_view()->browser()->SupportsWindowFeature( + Browser::FEATURE_WEBAPPFRAME); +} + +void BrowserNonClientFrameViewMus::LayoutAvatar() { + DCHECK(avatar_button()); +#if !defined(OS_CHROMEOS) + // ChromeOS shows avatar on V1 app. + DCHECK(browser_view()->IsTabStripVisible()); +#endif + gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon(); + gfx::Insets avatar_insets = GetLayoutInsets(AVATAR_ICON); + int avatar_bottom = GetTopInset(false) + browser_view()->GetTabStripHeight() - + avatar_insets.bottom(); + int avatar_y = avatar_bottom - incognito_icon.height(); + if (!ui::MaterialDesignController::IsModeMaterial() && + browser_view()->IsTabStripVisible() && + (frame()->IsMaximized() || frame()->IsFullscreen())) { + avatar_y = GetTopInset(false) + kContentShadowHeight; + } + + // Hide the incognito icon in immersive fullscreen when the tab light bar is + // visible because the header is too short for the icognito icon to be + // recognizable. + bool avatar_visible = !UseImmersiveLightbarHeaderStyle(); + int avatar_height = avatar_visible ? avatar_bottom - avatar_y : 0; + + gfx::Rect avatar_bounds(avatar_insets.left(), avatar_y, + incognito_icon.width(), avatar_height); + avatar_button()->SetBoundsRect(avatar_bounds); + avatar_button()->SetVisible(avatar_visible); +} + +#if defined(FRAME_AVATAR_BUTTON) +void BrowserNonClientFrameViewMus::LayoutNewStyleAvatar() { + DCHECK(new_avatar_button()); + + gfx::Size button_size = new_avatar_button()->GetPreferredSize(); + int button_x = width() - + caption_button_container_->GetPreferredSize().width() - + kNewAvatarButtonOffset - button_size.width(); + + new_avatar_button()->SetBounds( + button_x, 0, button_size.width(), + caption_button_container_->GetPreferredSize().height()); +} +#endif + +bool BrowserNonClientFrameViewMus::ShouldPaint() const { + if (!frame()->IsFullscreen()) + return true; + + // We need to paint when in immersive fullscreen and either: + // - The top-of-window views are revealed. + // - The lightbar style tabstrip is visible. + ImmersiveModeController* immersive_mode_controller = + browser_view()->immersive_mode_controller(); + return immersive_mode_controller->IsEnabled() && + (immersive_mode_controller->IsRevealed() || + UseImmersiveLightbarHeaderStyle()); +} + +void BrowserNonClientFrameViewMus::PaintImmersiveLightbarStyleHeader( + gfx::Canvas* canvas) {} + +void BrowserNonClientFrameViewMus::PaintToolbarBackground(gfx::Canvas* canvas) { + gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds()); + if (toolbar_bounds.IsEmpty()) + return; + gfx::Point toolbar_origin(toolbar_bounds.origin()); + View::ConvertPointToTarget(browser_view(), this, &toolbar_origin); + toolbar_bounds.set_origin(toolbar_origin); + + int x = toolbar_bounds.x(); + int w = toolbar_bounds.width(); + int y = toolbar_bounds.y(); + int h = toolbar_bounds.height(); + const ui::ThemeProvider* tp = GetThemeProvider(); + + if (ui::MaterialDesignController::IsModeMaterial()) { + // Paint the main toolbar image. Since this image is also used to draw the + // tab background, we must use the tab strip offset to compute the image + // source y position. If you have to debug this code use an image editor + // to paint a diagonal line through the toolbar image and ensure it lines up + // across the tab and toolbar. + gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR); + canvas->TileImageInt(*theme_toolbar, x + GetThemeBackgroundXInset(), + y - GetTopInset(false), x, y, w, + theme_toolbar->height()); + + // Draw the content/toolbar separator. + toolbar_bounds.Inset(kClientEdgeThickness, 0); + BrowserView::Paint1pxHorizontalLine( + canvas, ThemeProperties::GetDefaultColor( + ThemeProperties::COLOR_TOOLBAR_SEPARATOR), + toolbar_bounds, true); + } else { + // Gross hack: We split the toolbar images into two pieces, since sometimes + // (popup mode) the toolbar isn't tall enough to show the whole image. The + // split happens between the top shadow section and the bottom gradient + // section so that we never break the gradient. + // NOTE(pkotwicz): If the computation for |bottom_y| is changed, Layout() + // must be changed as well. + int split_point = kFrameShadowThickness * 2; + int bottom_y = y + split_point; + int bottom_edge_height = h - split_point; + + canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height), + tp->GetColor(ThemeProperties::COLOR_TOOLBAR)); + + // Paint the main toolbar image. Since this image is also used to draw the + // tab background, we must use the tab strip offset to compute the image + // source y position. If you have to debug this code use an image editor + // to paint a diagonal line through the toolbar image and ensure it lines up + // across the tab and toolbar. + gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR); + canvas->TileImageInt(*theme_toolbar, x + GetThemeBackgroundXInset(), + bottom_y - GetTopInset(false), x, bottom_y, w, + theme_toolbar->height()); + + // The pre-material design content area line has a shadow that extends a + // couple of pixels above the toolbar bounds. + const int kContentShadowHeight = 2; + gfx::ImageSkia* toolbar_top = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_TOP); + canvas->TileImageInt(*toolbar_top, 0, 0, x, y - kContentShadowHeight, w, + split_point + kContentShadowHeight + 1); + + // Draw the "lightening" shade line around the edges of the toolbar. + gfx::ImageSkia* toolbar_left = + tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_LEFT); + canvas->TileImageInt(*toolbar_left, 0, 0, x + kClientEdgeThickness, + y + kClientEdgeThickness + kContentShadowHeight, + toolbar_left->width(), theme_toolbar->height()); + gfx::ImageSkia* toolbar_right = + tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_RIGHT); + canvas->TileImageInt(*toolbar_right, 0, 0, + w - toolbar_right->width() - 2 * kClientEdgeThickness, + y + kClientEdgeThickness + kContentShadowHeight, + toolbar_right->width(), theme_toolbar->height()); + + // Draw the content/toolbar separator. + canvas->FillRect( + gfx::Rect(x + kClientEdgeThickness, + toolbar_bounds.bottom() - kClientEdgeThickness, + w - (2 * kClientEdgeThickness), kClientEdgeThickness), + ThemeProperties::GetDefaultColor( + ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); + } +} + +void BrowserNonClientFrameViewMus::PaintContentEdge(gfx::Canvas* canvas) { + DCHECK(!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle()); + const int bottom = frame_values().normal_insets.bottom(); + canvas->FillRect(gfx::Rect(0, bottom, width(), kClientEdgeThickness), + ThemeProperties::GetDefaultColor( + ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); +}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h new file mode 100644 index 0000000..d4a3fd2 --- /dev/null +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h
@@ -0,0 +1,128 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_MUS_H_ +#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_MUS_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" +#include "chrome/browser/ui/views/tab_icon_view_model.h" +#include "ui/views/controls/button/button.h" + +class TabIconView; +class WebAppLeftHeaderView; + +namespace views { +class ImageButton; +class ToggleImageButton; +} + +class BrowserNonClientFrameViewMus : public BrowserNonClientFrameView, + public TabIconViewModel, + public views::ButtonListener { + public: + static const char kViewClassName[]; + + BrowserNonClientFrameViewMus(BrowserFrame* frame, BrowserView* browser_view); + ~BrowserNonClientFrameViewMus() override; + + void Init(); + + // BrowserNonClientFrameView: + gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const override; + int GetTopInset(bool restored) const override; + int GetThemeBackgroundXInset() const override; + void UpdateThrobber(bool running) override; + void UpdateToolbar() override; + views::View* GetLocationIconView() const override; + + // views::NonClientFrameView: + gfx::Rect GetBoundsForClientView() const override; + gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const override; + int NonClientHitTest(const gfx::Point& point) override; + void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; + void ResetWindowControls() override; + void UpdateWindowIcon() override; + void UpdateWindowTitle() override; + void SizeConstraintsChanged() override; + + // views::View: + void OnPaint(gfx::Canvas* canvas) override; + void Layout() override; + const char* GetClassName() const override; + void GetAccessibleState(ui::AXViewState* state) override; + gfx::Size GetMinimumSize() const override; + void ChildPreferredSizeChanged(views::View* child) override; + + // TabIconViewModel: + bool ShouldTabIconViewAnimate() const override; + gfx::ImageSkia GetFaviconForTabIconView() override; + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + protected: + // BrowserNonClientFrameView: + void UpdateNewAvatarButtonImpl() override; + + private: + // views::NonClientFrameView: + bool DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const override; + + // Distance between the left edge of the NonClientFrameView and the tab strip. + int GetTabStripLeftInset() const; + + // Distance between the right edge of the NonClientFrameView and the tab + // strip. + int GetTabStripRightInset() const; + + // Returns true if we should use a super short header with light bars instead + // of regular tabs. This header is used in immersive fullscreen when the + // top-of-window views are not revealed. + bool UseImmersiveLightbarHeaderStyle() const; + + // Returns true if the header should be painted so that it looks the same as + // the header used for packaged apps. Packaged apps use a different color + // scheme than browser windows. + bool UsePackagedAppHeaderStyle() const; + + // Returns true if the header should be painted with a WebApp header style. + // The WebApp header style has a back button and title along with the usual + // accoutrements. + bool UseWebAppHeaderStyle() const; + + // Layout the avatar button. + void LayoutAvatar(); +#if defined(FRAME_AVATAR_BUTTON) + void LayoutNewStyleAvatar(); +#endif + + // Returns true if there is anything to paint. Some fullscreen windows do not + // need their frames painted. + bool ShouldPaint() const; + + // Paints the header background when the frame is in immersive fullscreen and + // tab light bar is visible. + void PaintImmersiveLightbarStyleHeader(gfx::Canvas* canvas); + + void PaintToolbarBackground(gfx::Canvas* canvas); + + // Draws the line under the header for windows without a toolbar and not using + // the packaged app header style. + void PaintContentEdge(gfx::Canvas* canvas); + + // The holder for the buttons on the left side of the header. This is included + // for web app style frames, and includes a back button and location icon. + WebAppLeftHeaderView* web_app_left_header_view_; + + // For popups, the window icon. + TabIconView* window_icon_; + + DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewMus); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_MUS_H_
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 2bdcbd79..57bf56c 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -351,6 +351,77 @@ }; //////////////////////////////////////////////////////////////////////////////// +// ThrobberView +// +// A Layer-backed view for updating a waiting or loading tab throbber. +class Tab::ThrobberView : public views::View { + public: + explicit ThrobberView(Tab* owner); + + // Resets the times tracking when the throbber changes state. + void ResetStartTimes(); + + private: + // views::View: + bool CanProcessEventsWithinSubtree() const override; + void OnPaint(gfx::Canvas* canvas) override; + + Tab* owner_; // Weak. Owns |this|. + + // The point in time when the tab icon was first painted in the waiting state. + base::TimeTicks waiting_start_time_; + + // The point in time when the tab icon was first painted in the loading state. + base::TimeTicks loading_start_time_; + + // Paint state for the throbber after the most recent waiting paint. + gfx::ThrobberWaitingState waiting_state_; + + DISALLOW_COPY_AND_ASSIGN(ThrobberView); +}; + +Tab::ThrobberView::ThrobberView(Tab* owner) : owner_(owner) {} + +void Tab::ThrobberView::ResetStartTimes() { + waiting_start_time_ = base::TimeTicks(); + loading_start_time_ = base::TimeTicks(); + waiting_state_ = gfx::ThrobberWaitingState(); +} + +bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { + return false; +} + +void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { + const TabRendererData::NetworkState state = owner_->data().network_state; + if (state == TabRendererData::NETWORK_STATE_NONE) + return; + + const ui::ThemeProvider* tp = GetThemeProvider(); + const gfx::Rect bounds = GetLocalBounds(); + if (state == TabRendererData::NETWORK_STATE_WAITING) { + if (waiting_start_time_ == base::TimeTicks()) + waiting_start_time_ = base::TimeTicks::Now(); + + waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_; + gfx::PaintThrobberWaiting( + canvas, bounds, + tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING), + waiting_state_.elapsed_time); + } else { + if (loading_start_time_ == base::TimeTicks()) + loading_start_time_ = base::TimeTicks::Now(); + + waiting_state_.color = + tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING); + gfx::PaintThrobberSpinningAfterWaiting( + canvas, bounds, + tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING), + base::TimeTicks::Now() - loading_start_time_, &waiting_state_); + } +} + +//////////////////////////////////////////////////////////////////////////////// // ImageCacheEntry Tab::ImageCacheEntry::ImageCacheEntry() @@ -381,6 +452,7 @@ favicon_hiding_offset_(0), immersive_loading_step_(0), should_display_crashed_favicon_(false), + throbber_(nullptr), media_indicator_button_(nullptr), close_button_(nullptr), title_(new views::Label()), @@ -411,6 +483,10 @@ SetEventTargeter( scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); + throbber_ = new ThrobberView(this); + throbber_->SetVisible(false); + AddChildView(throbber_); + media_indicator_button_ = new MediaIndicatorButton(this); AddChildView(media_indicator_button_); @@ -465,6 +541,7 @@ return; TabRendererData old(data_); + UpdateLoadingAnimation(data.network_state); data_ = data; base::string16 title = data_.title; @@ -524,9 +601,8 @@ return; } - TabRendererData::NetworkState old_state = data_.network_state; data_.network_state = state; - AdvanceLoadingAnimation(old_state, state); + AdvanceLoadingAnimation(); } void Tab::StartPulse() { @@ -815,6 +891,7 @@ favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); MaybeAdjustLeftForPinnedTab(&favicon_bounds_); } + throbber_->SetBoundsRect(favicon_bounds_); showing_close_button_ = ShouldShowCloseBox(); if (showing_close_button_) { @@ -1315,29 +1392,7 @@ return; if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { - // Paint network activity (aka throbber) animation frame. - const ui::ThemeProvider* tp = GetThemeProvider(); - if (data().network_state == TabRendererData::NETWORK_STATE_WAITING) { - if (waiting_start_time_ == base::TimeTicks()) - waiting_start_time_ = base::TimeTicks::Now(); - - waiting_state_.elapsed_time = - base::TimeTicks::Now() - waiting_start_time_; - gfx::PaintThrobberWaiting( - canvas, bounds, - tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING), - waiting_state_.elapsed_time); - } else { - if (loading_start_time_ == base::TimeTicks()) - loading_start_time_ = base::TimeTicks::Now(); - - waiting_state_.color = - tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_WAITING); - gfx::PaintThrobberSpinningAfterWaiting( - canvas, bounds, - tp->GetColor(ThemeProperties::COLOR_TAB_THROBBER_SPINNING), - base::TimeTicks::Now() - loading_start_time_, &waiting_state_); - } + // Throbber will do its own painting. } else { const gfx::ImageSkia& favicon = should_display_crashed_favicon_ ? *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( @@ -1351,27 +1406,46 @@ } } -void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, - TabRendererData::NetworkState state) { - if (state == TabRendererData::NETWORK_STATE_WAITING) { - // Waiting steps backwards. - immersive_loading_step_ = - (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % - kImmersiveLoadingStepCount; - } else if (state == TabRendererData::NETWORK_STATE_LOADING) { - immersive_loading_step_ = (immersive_loading_step_ + 1) % - kImmersiveLoadingStepCount; - } else { - waiting_start_time_ = base::TimeTicks(); - loading_start_time_ = base::TimeTicks(); - waiting_state_ = gfx::ThrobberWaitingState(); - immersive_loading_step_ = 0; - } +void Tab::AdvanceLoadingAnimation() { + const TabRendererData::NetworkState state = data().network_state; if (controller_->IsImmersiveStyle()) { + if (state == TabRendererData::NETWORK_STATE_WAITING) { + // Waiting steps backwards. + immersive_loading_step_ = + (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % + kImmersiveLoadingStepCount; + } else if (state == TabRendererData::NETWORK_STATE_LOADING) { + immersive_loading_step_ = + (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; + } else { + immersive_loading_step_ = 0; + } + SchedulePaintInRect(GetImmersiveBarRect()); - } else { - ScheduleIconPaint(); + return; } + + if (state == TabRendererData::NETWORK_STATE_NONE) { + throbber_->ResetStartTimes(); + throbber_->SetVisible(false); + ScheduleIconPaint(); + return; + } + + // Since the throbber can animate for a long time, paint to a separate layer + // when possible to reduce repaint overhead. + const bool paint_to_layer = controller_->CanPaintThrobberToLayer(); + if (paint_to_layer != !!throbber_->layer()) { + throbber_->SetPaintToLayer(paint_to_layer); + throbber_->SetFillsBoundsOpaquely(false); + if (paint_to_layer) + ScheduleIconPaint(); // Ensure the non-layered throbber goes away. + } + if (!throbber_->visible()) { + ScheduleIconPaint(); // Repaint the icon area to hide the favicon. + throbber_->SetVisible(true); + } + throbber_->SchedulePaint(); } int Tab::IconCapacity() const {
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h index e3f4814..850a864 100644 --- a/chrome/browser/ui/views/tabs/tab.h +++ b/chrome/browser/ui/views/tabs/tab.h
@@ -89,8 +89,7 @@ void SetData(const TabRendererData& data); const TabRendererData& data() const { return data_; } - // Sets the network state. If the network state changes NetworkStateChanged is - // invoked. + // Sets the network state. void UpdateLoadingAnimation(TabRendererData::NetworkState state); // Starts/Stops a pulse animation. @@ -161,15 +160,15 @@ private: friend class TabTest; - FRIEND_TEST_ALL_PREFIXES(TabTest, CloseButtonLayout); - friend class TabStripTest; FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked); FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabCloseButtonVisibilityWhenStacked); // The animation object used to swap the favicon with the sad tab icon. class FaviconCrashAnimation; + class TabCloseButton; + class ThrobberView; // Contains a cached image and the values used to generate it. struct ImageCacheEntry { @@ -259,8 +258,7 @@ void PaintIcon(gfx::Canvas* canvas); // Invoked if data_.network_state changes, or the network_state is not none. - void AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, - TabRendererData::NetworkState state); + void AdvanceLoadingAnimation(); // Returns the number of favicon-size elements that can fit in the tab's // current size. @@ -338,15 +336,6 @@ // crashes. int favicon_hiding_offset_; - // The point in time when the tab icon was first painted in the waiting state. - base::TimeTicks waiting_start_time_; - - // The point in time when the tab icon was first painted in the loading state. - base::TimeTicks loading_start_time_; - - // Paint state for the throbber after the most recent waiting paint. - gfx::ThrobberWaitingState waiting_state_; - // Step in the immersive loading progress indicator. int immersive_loading_step_; @@ -362,6 +351,7 @@ scoped_refptr<gfx::AnimationContainer> animation_container_; + ThrobberView* throbber_; MediaIndicatorButton* media_indicator_button_; views::ImageButton* close_button_; views::Label* title_;
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h index f8485e07..e3b8cc29 100644 --- a/chrome/browser/ui/views/tabs/tab_controller.h +++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -93,6 +93,11 @@ // set to the clip (if |clip| is empty means no clip). virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) = 0; + // Returns true if tab loading throbbers can be painted to a composited layer. + // This can only be done when the TabController can guarantee that nothing + // in the same window will redraw on top of the the favicon area of any tab. + virtual bool CanPaintThrobberToLayer() const = 0; + // Returns true if tabs painted in the rectangular light-bar style. virtual bool IsImmersiveStyle() const = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 4698d6f..52a3e73 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1200,6 +1200,13 @@ return true; } +bool TabStrip::CanPaintThrobberToLayer() const { + // Disable layer-painting of throbbers if dragging, if any tab animation is in + // progress, or if stacked tabs are enabled. + const bool dragging = drag_controller_ && drag_controller_->started_drag(); + return !touch_layout_ && !dragging && !IsAnimating(); +} + bool TabStrip::IsImmersiveStyle() const { return immersive_style_; }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 9bd8882..ec44b678 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -230,6 +230,7 @@ void OnMouseEventInTab(views::View* source, const ui::MouseEvent& event) override; bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override; + bool CanPaintThrobberToLayer() const override; bool IsImmersiveStyle() const override; int GetBackgroundResourceId(bool* custom_image) const override; void UpdateTabAccessibilityState(const Tab* tab,
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index 27dacf94..5f8eab7c 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -21,12 +21,13 @@ class FakeTabController : public TabController { public: - FakeTabController() : immersive_style_(false), active_tab_(false) { - } - ~FakeTabController() override {} + FakeTabController() {} void set_immersive_style(bool value) { immersive_style_ = value; } void set_active_tab(bool value) { active_tab_ = value; } + void set_paint_throbber_to_layer(bool value) { + paint_throbber_to_layer_ = value; + } const ui::ListSelectionModel& GetSelectionModel() const override { return selection_model_; @@ -60,6 +61,9 @@ void OnMouseEventInTab(views::View* source, const ui::MouseEvent& event) override {} bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override { return true; } + bool CanPaintThrobberToLayer() const override { + return paint_throbber_to_layer_; + } bool IsImmersiveStyle() const override { return immersive_style_; } int GetBackgroundResourceId(bool* custom_image) const override { *custom_image = false; @@ -70,8 +74,9 @@ private: ui::ListSelectionModel selection_model_; - bool immersive_style_; - bool active_tab_; + bool immersive_style_ = false; + bool active_tab_ = false; + bool paint_throbber_to_layer_ = true; DISALLOW_COPY_AND_ASSIGN(FakeTabController); }; @@ -98,6 +103,22 @@ base::i18n::SetICUDefaultLocale(original_locale_); } + static views::ImageButton* GetCloseButton(const Tab& tab) { + return tab.close_button_; + } + + static views::View* GetThrobberView(const Tab& tab) { + // Reinterpret to keep the definition encapsulated (which works so long as + // multiple inheritance isn't involved). + return reinterpret_cast<views::View*>(tab.throbber_); + } + + static gfx::Rect GetFaviconBounds(const Tab& tab) { + return tab.favicon_bounds_; + } + + static void LayoutTab(Tab* tab) { tab->Layout(); } + static void CheckForExpectedLayoutAndVisibilityOfElements(const Tab& tab) { // Check whether elements are visible when they are supposed to be, given // Tab size and TabRendererData state. @@ -398,17 +419,78 @@ FakeTabController tab_controller; Tab tab(&tab_controller); tab.SetBounds(0, 0, 100, 50); - tab.Layout(); - gfx::Insets close_button_insets = tab.close_button_->GetInsets(); - tab.Layout(); - gfx::Insets close_button_insets_2 = tab.close_button_->GetInsets(); + LayoutTab(&tab); + gfx::Insets close_button_insets = GetCloseButton(tab)->GetInsets(); + LayoutTab(&tab); + gfx::Insets close_button_insets_2 = GetCloseButton(tab)->GetInsets(); EXPECT_EQ(close_button_insets.top(), close_button_insets_2.top()); EXPECT_EQ(close_button_insets.left(), close_button_insets_2.left()); EXPECT_EQ(close_button_insets.bottom(), close_button_insets_2.bottom()); EXPECT_EQ(close_button_insets.right(), close_button_insets_2.right()); // Also make sure the close button is sized as large as the tab. - EXPECT_EQ(50, tab.close_button_->bounds().height()); + EXPECT_EQ(50, GetCloseButton(tab)->bounds().height()); +} + +// Tests expected changes to the ThrobberView state when the WebContents loading +// state changes or the animation timer (usually in BrowserView) triggers. +TEST_P(TabTest, LayeredThrobber) { + if (testing_for_rtl_locale() && !base::i18n::IsRTL()) { + LOG(WARNING) << "Testing of RTL locale not supported on current platform."; + return; + } + + Widget widget; + InitWidget(&widget); + + FakeTabController tab_controller; + Tab tab(&tab_controller); + widget.GetContentsView()->AddChildView(&tab); + tab.SetBoundsRect(gfx::Rect(Tab::GetStandardSize())); + + views::View* throbber = GetThrobberView(tab); + EXPECT_FALSE(throbber->visible()); + EXPECT_EQ(TabRendererData::NETWORK_STATE_NONE, tab.data().network_state); + EXPECT_EQ(throbber->bounds(), GetFaviconBounds(tab)); + + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + EXPECT_FALSE(throbber->visible()); + + // Simulate a "normal" tab load: should paint to a layer. + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + EXPECT_TRUE(tab_controller.CanPaintThrobberToLayer()); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_LOADING); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + EXPECT_FALSE(throbber->visible()); + + // Simulate a drag started and stopped during a load: layer painting stops + // temporarily. + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + tab_controller.set_paint_throbber_to_layer(false); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + EXPECT_TRUE(throbber->visible()); + EXPECT_FALSE(throbber->layer()); + tab_controller.set_paint_throbber_to_layer(true); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + EXPECT_TRUE(throbber->visible()); + EXPECT_TRUE(throbber->layer()); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + EXPECT_FALSE(throbber->visible()); + + // Simulate a tab load starting and stopping during tab dragging (or with + // stacked tabs): no layer painting. + tab_controller.set_paint_throbber_to_layer(false); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_WAITING); + EXPECT_TRUE(throbber->visible()); + EXPECT_FALSE(throbber->layer()); + tab.UpdateLoadingAnimation(TabRendererData::NETWORK_STATE_NONE); + EXPECT_FALSE(throbber->visible()); } // Test in both a LTR and a RTL locale. Note: The fact that the UI code is
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc index 07868e0..d17af84 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
@@ -38,6 +38,7 @@ #include "ui/gfx/geometry/insets.h" #include "ui/gfx/image/image.h" #include "ui/resources/grit/ui_resources.h" +#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/button/menu_button_listener.h" @@ -159,6 +160,8 @@ ~InternalPageInfoPopupView() override; // views::BubbleDelegateView: + views::NonClientFrameView* CreateNonClientFrameView( + views::Widget* widget) override; void OnWidgetDestroying(views::Widget* widget) override; private: @@ -292,12 +295,13 @@ set_anchor_view_insets(gfx::Insets(kLocationIconVerticalMargin, 0, kLocationIconVerticalMargin, 0)); - const int kSpacing = 4; + const int kSpacing = 16; SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, kSpacing, kSpacing, kSpacing)); + set_margins(gfx::Insets()); views::ImageView* icon_view = new views::ImageView(); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - icon_view->SetImage(rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_26)); + icon_view->SetImage(rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_16)); AddChildView(icon_view); views::Label* label = @@ -313,6 +317,16 @@ InternalPageInfoPopupView::~InternalPageInfoPopupView() { } +views::NonClientFrameView* InternalPageInfoPopupView::CreateNonClientFrameView( + views::Widget* widget) { + views::BubbleFrameView* frame = static_cast<views::BubbleFrameView*>( + BubbleDelegateView::CreateNonClientFrameView(widget)); + // 16px padding + half of icon width comes out to 24px. + frame->bubble_border()->set_arrow_offset( + 24 + frame->bubble_border()->GetBorderThickness()); + return frame; +} + void InternalPageInfoPopupView::OnWidgetDestroying(views::Widget* widget) { is_popup_showing = false; }
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h index 4ae4f9c..d2581b1 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h
@@ -92,7 +92,7 @@ const gfx::Range& range, int event_flags) override; - // views::TabbedPaneListener implementations. + // views::TabbedPaneListener implementation. void TabSelectedAt(int index) override; // views::View implementation.
diff --git a/chrome/browser/ui/webui/flags_ui.cc b/chrome/browser/ui/webui/flags_ui.cc index 0cd3433..48c7920 100644 --- a/chrome/browser/ui/webui/flags_ui.cc +++ b/chrome/browser/ui/webui/flags_ui.cc
@@ -31,8 +31,8 @@ #include "grit/components_chromium_strings.h" #include "grit/components_google_chrome_strings.h" #include "grit/components_resources.h" +#include "grit/components_scaled_resources.h" #include "grit/components_strings.h" -#include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc new file mode 100644 index 0000000..b163644 --- /dev/null +++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -0,0 +1,394 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h" + +#include <iterator> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/i18n/rtl.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "base/value_conversions.h" +#include "base/values.h" +#include "chrome/browser/download/all_download_item_notifier.h" +#include "chrome/browser/download/download_crx_util.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/download/download_query.h" +#include "chrome/browser/extensions/api/downloads/downloads_api.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/download_item.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/web_ui.h" +#include "extensions/browser/extension_system.h" +#include "net/base/filename_util.h" +#include "third_party/icu/source/i18n/unicode/datefmt.h" +#include "ui/base/l10n/time_format.h" + +using content::BrowserContext; +using content::DownloadItem; +using content::DownloadManager; + +using DownloadVector = DownloadManager::DownloadVector; + +namespace { + +// Returns a string constant to be used as the |danger_type| value in +// CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE, +// DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the +// |danger_type| value is only defined if the value of |state| is |DANGEROUS|. +const char* GetDangerTypeString(content::DownloadDangerType danger_type) { + switch (danger_type) { + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: + return "DANGEROUS_FILE"; + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: + return "DANGEROUS_URL"; + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: + return "DANGEROUS_CONTENT"; + case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: + return "UNCOMMON_CONTENT"; + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: + return "DANGEROUS_HOST"; + case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: + return "POTENTIALLY_UNWANTED"; + case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: + case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: + case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: + case content::DOWNLOAD_DANGER_TYPE_MAX: + break; + } + // Don't return a danger type string if it is NOT_DANGEROUS, + // MAYBE_DANGEROUS_CONTENT, or USER_VALIDATED. + NOTREACHED(); + return ""; +} + +// TODO(dbeam): if useful elsewhere, move to base/i18n/time_formatting.h? +base::string16 TimeFormatLongDate(const base::Time& time) { + scoped_ptr<icu::DateFormat> formatter( + icu::DateFormat::createDateInstance(icu::DateFormat::kLong)); + icu::UnicodeString date_string; + formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); + return base::string16(date_string.getBuffer(), + static_cast<size_t>(date_string.length())); +} + +} // namespace + +DownloadsListTracker::DownloadsListTracker( + DownloadManager* download_manager, + content::WebUI* web_ui) + : main_notifier_(download_manager, this), + web_ui_(web_ui), + should_show_(base::Bind(&DownloadsListTracker::ShouldShow, + base::Unretained(this))) { + Init(); +} + +DownloadsListTracker::~DownloadsListTracker() {} + +void DownloadsListTracker::CallClearAll() { + if (sending_updates_) + web_ui_->CallJavascriptFunction("downloads.Manager.clearAll"); +} + +bool DownloadsListTracker::SetSearchTerms(const base::ListValue& search_terms) { + std::vector<base::string16> new_terms; + new_terms.resize(search_terms.GetSize()); + + for (size_t i = 0; i < search_terms.GetSize(); ++i) + search_terms.GetString(i, &new_terms[i]); + + if (new_terms == search_terms_) + return false; + + search_terms_.swap(new_terms); + RebuildSortedSet(); + return true; +} + +void DownloadsListTracker::Start() { + sending_updates_ = true; + + // TODO(dbeam): paging and limiting logic. + + base::ListValue list; + for (auto* item : sorted_visible_items_) + list.Append(CreateDownloadItemValue(item).Pass()); + + web_ui_->CallJavascriptFunction("downloads.Manager.insertItems", + base::FundamentalValue(0), list); +} + +void DownloadsListTracker::Stop() { + sending_updates_ = false; +} + +DownloadManager* DownloadsListTracker::GetMainNotifierManager() const { + return main_notifier_.GetManager(); +} + +DownloadManager* DownloadsListTracker::GetOriginalNotifierManager() const { + return original_notifier_ ? original_notifier_->GetManager() : nullptr; +} + +void DownloadsListTracker::OnDownloadCreated(DownloadManager* manager, + DownloadItem* download_item) { + if (should_show_.Run(*download_item)) + CallInsertItem(sorted_visible_items_.insert(download_item).first); +} + +void DownloadsListTracker::OnDownloadUpdated(DownloadManager* manager, + DownloadItem* download_item) { + auto current_position = sorted_visible_items_.find(download_item); + bool is_showing = current_position != sorted_visible_items_.end(); + bool should_show = should_show_.Run(*download_item); + + if (!is_showing && should_show) + CallInsertItem(sorted_visible_items_.insert(download_item).first); + else if (is_showing && !should_show) + RemoveItem(current_position); + else if (is_showing) + CallUpdateItem(current_position); +} + +void DownloadsListTracker::OnDownloadRemoved(DownloadManager* manager, + DownloadItem* download_item) { + auto current_position = sorted_visible_items_.find(download_item); + if (current_position != sorted_visible_items_.end()) + RemoveItem(current_position); +} + +DownloadsListTracker::DownloadsListTracker( + DownloadManager* download_manager, + content::WebUI* web_ui, + base::Callback<bool(const DownloadItem&)> should_show) + : main_notifier_(download_manager, this), + web_ui_(web_ui), + should_show_(should_show) { + Init(); +} + +scoped_ptr<base::DictionaryValue> DownloadsListTracker::CreateDownloadItemValue( + content::DownloadItem* download_item) const { + // TODO(asanka): Move towards using download_model here for getting status and + // progress. The difference currently only matters to Drive downloads and + // those don't show up on the downloads page, but should. + DownloadItemModel download_model(download_item); + + // The items which are to be written into file_value are also described in + // chrome/browser/resources/downloads/downloads.js in @typedef for + // BackendDownloadObject. Please update it whenever you add or remove + // any keys in file_value. + scoped_ptr<base::DictionaryValue> file_value(new base::DictionaryValue); + + file_value->SetInteger( + "started", static_cast<int>(download_item->GetStartTime().ToTimeT())); + file_value->SetString( + "since_string", ui::TimeFormat::RelativeDate( + download_item->GetStartTime(), NULL)); + file_value->SetString( + "date_string", TimeFormatLongDate(download_item->GetStartTime())); + + file_value->SetString("id", base::Uint64ToString(download_item->GetId())); + + base::FilePath download_path(download_item->GetTargetFilePath()); + file_value->Set("file_path", base::CreateFilePathValue(download_path)); + file_value->SetString("file_url", + net::FilePathToFileURL(download_path).spec()); + + extensions::DownloadedByExtension* by_ext = + extensions::DownloadedByExtension::Get(download_item); + std::string by_ext_id; + std::string by_ext_name; + if (by_ext) { + by_ext_id = by_ext->id(); + // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16? + by_ext_name = by_ext->name(); + + // Lookup the extension's current name() in case the user changed their + // language. This won't work if the extension was uninstalled, so the name + // might be the wrong language. + bool include_disabled = true; + const extensions::Extension* extension = extensions::ExtensionSystem::Get( + Profile::FromBrowserContext(download_item->GetBrowserContext()))-> + extension_service()->GetExtensionById(by_ext->id(), include_disabled); + if (extension) + by_ext_name = extension->name(); + } + file_value->SetString("by_ext_id", by_ext_id); + file_value->SetString("by_ext_name", by_ext_name); + + // Keep file names as LTR. TODO(dbeam): why? + base::string16 file_name = + download_item->GetFileNameToReportUser().LossyDisplayName(); + file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); + file_value->SetString("file_name", file_name); + file_value->SetString("url", download_item->GetURL().spec()); + file_value->SetInteger("total", static_cast<int>( + download_item->GetTotalBytes())); + file_value->SetBoolean("file_externally_removed", + download_item->GetFileExternallyRemoved()); + file_value->SetBoolean("resume", download_item->CanResume()); + + bool incognito = false; + auto* original_manager = GetOriginalNotifierManager(); + if (original_manager) { + incognito = + original_manager->GetDownload(download_item->GetId()) == download_item; + } + file_value->SetBoolean("otr", incognito); + + const char* danger_type = ""; + base::string16 last_reason_text; + // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress. + int percent = -2; + base::string16 progress_status_text; + bool retry = false; + const char* state = nullptr; + + switch (download_item->GetState()) { + case content::DownloadItem::IN_PROGRESS: { + if (download_item->IsDangerous()) { + state = "DANGEROUS"; + danger_type = GetDangerTypeString(download_item->GetDangerType()); + } else if (download_item->IsPaused()) { + state = "PAUSED"; + } else { + state = "IN_PROGRESS"; + } + progress_status_text = download_model.GetTabProgressStatusText(); + percent = download_item->PercentComplete(); + break; + } + + case content::DownloadItem::INTERRUPTED: + state = "INTERRUPTED"; + progress_status_text = download_model.GetTabProgressStatusText(); + + if (download_item->CanResume()) + percent = download_item->PercentComplete(); + + last_reason_text = download_model.GetInterruptReasonText(); + if (content::DOWNLOAD_INTERRUPT_REASON_CRASH == + download_item->GetLastReason() && !download_item->CanResume()) { + retry = true; + } + break; + + case content::DownloadItem::CANCELLED: + state = "CANCELLED"; + retry = true; + break; + + case content::DownloadItem::COMPLETE: + DCHECK(!download_item->IsDangerous()); + state = "COMPLETE"; + break; + + case content::DownloadItem::MAX_DOWNLOAD_STATE: + NOTREACHED(); + } + + DCHECK(state); + + file_value->SetString("danger_type", danger_type); + file_value->SetString("last_reason_text", last_reason_text); + file_value->SetInteger("percent", percent); + file_value->SetString("progress_status_text", progress_status_text); + file_value->SetBoolean("retry", retry); + file_value->SetString("state", state); + + return file_value.Pass(); +} + +const DownloadItem* DownloadsListTracker::GetItemForTesting(size_t index) + const { + if (index >= sorted_visible_items_.size()) + return nullptr; + + SortedSet::iterator it = sorted_visible_items_.begin(); + std::advance(it, index); + return *it; +} + +bool DownloadsListTracker::ShouldShow(const DownloadItem& item) const { + return !download_crx_util::IsExtensionDownload(item) && + !item.IsTemporary() && + !item.GetFileNameToReportUser().empty() && + !item.GetTargetFilePath().empty() && + DownloadItemModel(const_cast<DownloadItem*>(&item)).ShouldShowInShelf() && + DownloadQuery::MatchesQuery(search_terms_, item); +} + +bool DownloadsListTracker::StartTimeComparator::operator() ( + const content::DownloadItem* a, const content::DownloadItem* b) const { + return a->GetStartTime() > b->GetStartTime(); +} + +void DownloadsListTracker::Init() { + Profile* profile = Profile::FromBrowserContext( + GetMainNotifierManager()->GetBrowserContext()); + if (profile->IsOffTheRecord()) { + original_notifier_.reset(new AllDownloadItemNotifier( + BrowserContext::GetDownloadManager(profile->GetOriginalProfile()), + this)); + } + + RebuildSortedSet(); +} + +void DownloadsListTracker::RebuildSortedSet() { + DownloadVector all_items, visible_items; + + GetMainNotifierManager()->GetAllDownloads(&all_items); + + if (GetOriginalNotifierManager()) + GetOriginalNotifierManager()->GetAllDownloads(&all_items); + + DownloadQuery query; + query.AddFilter(should_show_); + query.Search(all_items.begin(), all_items.end(), &visible_items); + + SortedSet sorted_visible_items(visible_items.begin(), visible_items.end()); + sorted_visible_items_.swap(sorted_visible_items); +} + +void DownloadsListTracker::CallInsertItem(const SortedSet::iterator& insert) { + if (!sending_updates_) + return; + + base::ListValue list; + list.Append(CreateDownloadItemValue(*insert).Pass()); + + web_ui_->CallJavascriptFunction("downloads.Manager.insertItems", + base::FundamentalValue(GetIndex(insert)), + list); +} + +void DownloadsListTracker::CallUpdateItem(const SortedSet::iterator& update) { + if (!sending_updates_) + return; + + web_ui_->CallJavascriptFunction("downloads.Manager.updateItem", + base::FundamentalValue(GetIndex(update)), + *CreateDownloadItemValue(*update)); +} + +int DownloadsListTracker::GetIndex(const SortedSet::iterator& position) const { + // TODO(dbeam): this could be log(N) if |position| was random access. + return std::distance(sorted_visible_items_.begin(), position); +} + +void DownloadsListTracker::RemoveItem(const SortedSet::iterator& remove) { + if (sending_updates_) { + web_ui_->CallJavascriptFunction("downloads.Manager.removeItem", + base::FundamentalValue(GetIndex(remove))); + } + sorted_visible_items_.erase(remove); +}
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h new file mode 100644 index 0000000..05399b3 --- /dev/null +++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
@@ -0,0 +1,125 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_MD_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_ +#define CHROME_BROWSER_UI_WEBUI_MD_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_ + +#include <set> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string16.h" +#include "base/time/time.h" +#include "base/values.h" +#include "chrome/browser/download/all_download_item_notifier.h" +#include "content/public/browser/download_item.h" + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace content { +class DownloadManager; +class WebUI; +} + +// A class that tracks all downloads activity and keeps a sorted representation +// of the downloads as chrome://downloads wants to display them. +class DownloadsListTracker : public AllDownloadItemNotifier::Observer { + public: + DownloadsListTracker(content::DownloadManager* download_manager, + content::WebUI* web_ui); + ~DownloadsListTracker() override; + + // Clears all downloads on the page (if it's ready). + void CallClearAll(); + + // Shows only downloads that match |search_terms|. An empty list shows all + // downloads. Returns whether |search_terms.Equals(&search_terms_)|. + bool SetSearchTerms(const base::ListValue& search_terms); + + // Sends all downloads and enables updates. + void Start(); + + // Stops sending updates to the page. + void Stop(); + + content::DownloadManager* GetMainNotifierManager() const; + content::DownloadManager* GetOriginalNotifierManager() const; + + // AllDownloadItemNotifier::Observer: + void OnDownloadCreated(content::DownloadManager* manager, + content::DownloadItem* download_item) override; + void OnDownloadUpdated(content::DownloadManager* manager, + content::DownloadItem* download_item) override; + void OnDownloadRemoved(content::DownloadManager* manager, + content::DownloadItem* download_item) override; + + protected: + // Testing constructor. + DownloadsListTracker(content::DownloadManager* download_manager, + content::WebUI* web_ui, + base::Callback<bool(const content::DownloadItem&)>); + + // Creates a dictionary value that's sent to the page as JSON. + virtual scoped_ptr<base::DictionaryValue> CreateDownloadItemValue( + content::DownloadItem* item) const; + + const content::DownloadItem* GetItemForTesting(size_t index) const; + + private: + struct StartTimeComparator { + bool operator() (const content::DownloadItem* a, + const content::DownloadItem* b) const; + }; + using SortedSet = std::set<content::DownloadItem*, StartTimeComparator>; + + // Called by both constructors to initialize common state. + void Init(); + + // Clears and re-inserts all visible items in a sorted order into + // |sorted_visible_items_|. + void RebuildSortedSet(); + + // Whether |item| should show on the current page. + bool ShouldShow(const content::DownloadItem& item) const; + + // Gets a page index for |position| from |sorted_visible_items_|. + int GetIndex(const SortedSet::iterator& position) const; + + // Calls "insertItems" if |sending_updates_|. + void CallInsertItem(const SortedSet::iterator& insert); + + // Calls "updateItem" if |sending_updates_|. + void CallUpdateItem(const SortedSet::iterator& update); + + // Removes the item that corresponds to |remove| and sends a "removeItems" + // message to the page if |sending_updates_|. + void RemoveItem(const SortedSet::iterator& remove); + + AllDownloadItemNotifier main_notifier_; + scoped_ptr<AllDownloadItemNotifier> original_notifier_; + + // The WebUI object corresponding to the page we care about. + content::WebUI* const web_ui_; + + // Callback used to determine if an item should show on the page. Set to + // |ShouldShow()| in default constructor, passed in while testing. + base::Callback<bool(const content::DownloadItem&)> should_show_; + + // When this is true, all changes to downloads that affect the page are sent + // via JavaScript. + bool sending_updates_ = false; + + SortedSet sorted_visible_items_; + + // Current search terms. + std::vector<base::string16> search_terms_; + + DISALLOW_COPY_AND_ASSIGN(DownloadsListTracker); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_MD_DOWNLOADS_DOWNLOADS_LIST_TRACKER_H_
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc new file mode 100644 index 0000000..fef30f3 --- /dev/null +++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
@@ -0,0 +1,276 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h" + +#include <vector> + +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/stl_util.h" +#include "base/time/time.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/mock_download_item.h" +#include "content/public/test/mock_download_manager.h" +#include "content/public/test/test_browser_thread.h" +#include "content/public/test/test_web_ui.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::DownloadItem; +using content::MockDownloadItem; +using DownloadVector = std::vector<DownloadItem*>; +using testing::_; +using testing::Return; + +namespace { + +uint64 GetId(const base::Value* value) { + const base::DictionaryValue* dict; + CHECK(value->GetAsDictionary(&dict)); + + int id; + CHECK(dict->GetInteger("id", &id)); + CHECK_GE(id, 0); + return static_cast<uint64>(id); +} + +std::vector<uint64> GetIds(const base::Value* value) { + CHECK(value); + + std::vector<uint64> ids; + + if (value->GetType() == base::Value::TYPE_LIST) { + const base::ListValue* list; + value->GetAsList(&list); + + for (auto* list_item : *list) + ids.push_back(GetId(list_item)); + } else { + ids.push_back(GetId(value)); + } + + return ids; +} + +int GetIndex(const base::Value* value) { + CHECK(value); + int index; + CHECK(value->GetAsInteger(&index)); + return index; +} + +bool ShouldShowItem(const DownloadItem& item) { + DownloadItemModel model(const_cast<DownloadItem*>(&item)); + return model.ShouldShowInShelf(); +} + +} // namespace + +// A test version of DownloadsListTracker. +class TestDownloadsListTracker : public DownloadsListTracker { + public: + TestDownloadsListTracker(content::DownloadManager* manager, + content::WebUI* web_ui) + : DownloadsListTracker(manager, web_ui, base::Bind(&ShouldShowItem)) {} + ~TestDownloadsListTracker() override {} + + using DownloadsListTracker::GetItemForTesting; + + protected: + scoped_ptr<base::DictionaryValue> CreateDownloadItemValue( + content::DownloadItem* item) const override { + scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); + CHECK_LE(item->GetId(), static_cast<uint64>(INT_MAX)); + dict->SetInteger("id", item->GetId()); + return dict.Pass(); + } +}; + +// A fixture to test DownloadsListTracker. +class DownloadsListTrackerTest : public testing::Test { + public: + DownloadsListTrackerTest() + : ui_thread_(content::BrowserThread::UI, &message_loop_) {} + ~DownloadsListTrackerTest() override { + for (auto* mock_item : mock_items_) + testing::Mock::VerifyAndClear(mock_item); + STLDeleteElements(&mock_items_); + } + + // testing::Test: + void SetUp() override { + ON_CALL(manager_, GetBrowserContext()).WillByDefault(Return(&profile_)); + ON_CALL(manager_, GetAllDownloads(_)).WillByDefault( + testing::Invoke(this, &DownloadsListTrackerTest::GetAllDownloads)); + } + + MockDownloadItem* CreateMock(uint64 id, const base::Time& started) { + MockDownloadItem* new_item = new testing::NiceMock<MockDownloadItem>(); + mock_items_.push_back(new_item); + + ON_CALL(*new_item, GetId()).WillByDefault(Return(id)); + ON_CALL(*new_item, GetStartTime()).WillByDefault(Return(started)); + + return new_item; + } + + MockDownloadItem* CreateNextItem() { + return CreateMock(mock_items_.size(), base::Time::UnixEpoch() + + base::TimeDelta::FromHours(mock_items_.size())); + } + + void CreateTracker() { + tracker_.reset(new TestDownloadsListTracker(manager(), web_ui())); + } + + content::DownloadManager* manager() { return &manager_; } + content::TestWebUI* web_ui() { return &web_ui_; } + TestDownloadsListTracker* tracker() { return tracker_.get(); } + + private: + void GetAllDownloads(DownloadVector* result) { + for (auto* mock_item : mock_items_) + result->push_back(mock_item); + } + + // NOTE: The initialization order of these members matters. + base::MessageLoopForUI message_loop_; + content::TestBrowserThread ui_thread_; + TestingProfile profile_; + + testing::NiceMock<content::MockDownloadManager> manager_; + content::TestWebUI web_ui_; + scoped_ptr<TestDownloadsListTracker> tracker_; + + std::vector<MockDownloadItem*> mock_items_; +}; + +TEST_F(DownloadsListTrackerTest, SetSearchTerms) { + CreateTracker(); + + const base::ListValue empty_terms; + EXPECT_FALSE(tracker()->SetSearchTerms(empty_terms)); + + base::ListValue search_terms; + search_terms.AppendString("search"); + EXPECT_TRUE(tracker()->SetSearchTerms(search_terms)); + + EXPECT_FALSE(tracker()->SetSearchTerms(search_terms)); + + EXPECT_TRUE(tracker()->SetSearchTerms(empty_terms)); + + // Notifying the page is left up to the handler in this case. + EXPECT_TRUE(web_ui()->call_data().empty()); +} + +TEST_F(DownloadsListTrackerTest, StartCallsInsertItems) { + DownloadItem* first_item = CreateNextItem(); + + CreateTracker(); + ASSERT_TRUE(tracker()->GetItemForTesting(0)); + EXPECT_TRUE(web_ui()->call_data().empty()); + + tracker()->Start(); + ASSERT_FALSE(web_ui()->call_data().empty()); + + EXPECT_EQ("downloads.Manager.insertItems", + web_ui()->call_data()[0]->function_name()); + EXPECT_EQ(0, GetIndex(web_ui()->call_data()[0]->arg1())); + + std::vector<uint64> ids = GetIds(web_ui()->call_data()[0]->arg2()); + ASSERT_FALSE(ids.empty()); + EXPECT_EQ(first_item->GetId(), ids[0]); +} + +// The page is in a loading state until it gets an insertItems call. Ensure that +// happens even without downloads. +TEST_F(DownloadsListTrackerTest, EmptyGetAllItemsStillCallsInsertItems) { + CreateTracker(); + + ASSERT_FALSE(tracker()->GetItemForTesting(0)); + ASSERT_TRUE(web_ui()->call_data().empty()); + + tracker()->Start(); + + ASSERT_FALSE(web_ui()->call_data().empty()); + EXPECT_EQ("downloads.Manager.insertItems", + web_ui()->call_data()[0]->function_name()); + ASSERT_TRUE(web_ui()->call_data()[0]->arg2()); + EXPECT_TRUE(GetIds(web_ui()->call_data()[0]->arg2()).empty()); +} + +TEST_F(DownloadsListTrackerTest, OnDownloadCreatedCallsInsertItems) { + CreateTracker(); + tracker()->Start(); + web_ui()->ClearTrackedCalls(); + + ASSERT_FALSE(tracker()->GetItemForTesting(0)); + DownloadItem* first_item = CreateNextItem(); + tracker()->OnDownloadCreated(manager(), first_item); + + ASSERT_FALSE(web_ui()->call_data().empty()); + EXPECT_EQ("downloads.Manager.insertItems", + web_ui()->call_data()[0]->function_name()); + EXPECT_EQ(0, GetIndex(web_ui()->call_data()[0]->arg1())); + + std::vector<uint64> ids = GetIds(web_ui()->call_data()[0]->arg2()); + ASSERT_FALSE(ids.empty()); + EXPECT_EQ(first_item->GetId(), ids[0]); +} + +TEST_F(DownloadsListTrackerTest, OnDownloadRemovedCallsRemoveItem) { + DownloadItem* first_item = CreateNextItem(); + + CreateTracker(); + tracker()->Start(); + web_ui()->ClearTrackedCalls(); + + EXPECT_TRUE(tracker()->GetItemForTesting(0)); + tracker()->OnDownloadRemoved(manager(), first_item); + EXPECT_FALSE(tracker()->GetItemForTesting(0)); + + ASSERT_FALSE(web_ui()->call_data().empty()); + + EXPECT_EQ("downloads.Manager.removeItem", + web_ui()->call_data()[0]->function_name()); + EXPECT_EQ(0, GetIndex(web_ui()->call_data()[0]->arg1())); +} + +TEST_F(DownloadsListTrackerTest, OnDownloadUpdatedCallsRemoveItem) { + DownloadItem* first_item = CreateNextItem(); + + CreateTracker(); + tracker()->Start(); + web_ui()->ClearTrackedCalls(); + + EXPECT_TRUE(tracker()->GetItemForTesting(0)); + + DownloadItemModel(first_item).SetShouldShowInShelf(false); + tracker()->OnDownloadUpdated(manager(), first_item); + + EXPECT_FALSE(tracker()->GetItemForTesting(0)); + + ASSERT_FALSE(web_ui()->call_data().empty()); + + EXPECT_EQ("downloads.Manager.removeItem", + web_ui()->call_data()[0]->function_name()); + EXPECT_EQ(0, GetIndex(web_ui()->call_data()[0]->arg1())); +} + +TEST_F(DownloadsListTrackerTest, StartExcludesHiddenItems) { + DownloadItem* first_item = CreateNextItem(); + DownloadItemModel(first_item).SetShouldShowInShelf(false); + + CreateTracker(); + tracker()->Start(); + + ASSERT_FALSE(web_ui()->call_data().empty()); + + EXPECT_EQ("downloads.Manager.insertItems", + web_ui()->call_data()[0]->function_name()); + EXPECT_TRUE(GetIds(web_ui()->call_data()[0]->arg2()).empty()); +}
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc index 403cbbf..39d3cc3f 100644 --- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc +++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
@@ -11,10 +11,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/i18n/rtl.h" -#include "base/i18n/time_formatting.h" #include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" @@ -22,10 +19,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/supports_user_data.h" #include "base/threading/thread.h" -#include "base/value_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/download/download_crx_util.h" #include "chrome/browser/download/download_danger_prompt.h" #include "chrome/browser/download/download_history.h" #include "chrome/browser/download/download_item_model.h" @@ -34,8 +29,6 @@ #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/download/drag_download_item.h" -#include "chrome/browser/extensions/api/downloads/downloads_api.h" -#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/fileicon_source.h" @@ -44,26 +37,20 @@ #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item.h" +#include "content/public/browser/download_manager.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" -#include "extensions/browser/extension_system.h" #include "net/base/filename_util.h" -#include "third_party/icu/source/i18n/unicode/datefmt.h" #include "ui/base/l10n/time_format.h" #include "ui/gfx/image/image.h" using base::UserMetricsAction; -using content::BrowserContext; using content::BrowserThread; namespace { -// Maximum number of downloads to show. TODO(glen): Remove this and instead -// stuff the downloads down the pipe slowly. -size_t kMaxNumberOfDownloads = 150; - enum DownloadsDOMEvent { DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, @@ -86,203 +73,11 @@ DOWNLOADS_DOM_EVENT_MAX); } -// Returns a string constant to be used as the |danger_type| value in -// CreateDownloadItemValue(). Only return strings for DANGEROUS_FILE, -// DANGEROUS_URL, DANGEROUS_CONTENT, and UNCOMMON_CONTENT because the -// |danger_type| value is only defined if the value of |state| is |DANGEROUS|. -const char* GetDangerTypeString(content::DownloadDangerType danger_type) { - switch (danger_type) { - case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: - return "DANGEROUS_FILE"; - case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: - return "DANGEROUS_URL"; - case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: - return "DANGEROUS_CONTENT"; - case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: - return "UNCOMMON_CONTENT"; - case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: - return "DANGEROUS_HOST"; - case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: - return "POTENTIALLY_UNWANTED"; - default: - // Don't return a danger type string if it is NOT_DANGEROUS or - // MAYBE_DANGEROUS_CONTENT. - NOTREACHED(); - return ""; - } -} - -// TODO(dbeam): if useful elsewhere, move to base/i18n/time_formatting.h? -base::string16 TimeFormatLongDate(const base::Time& time) { - scoped_ptr<icu::DateFormat> formatter( - icu::DateFormat::createDateInstance(icu::DateFormat::kLong)); - icu::UnicodeString date_string; - formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); - return base::string16(date_string.getBuffer(), - static_cast<size_t>(date_string.length())); -} - -// Returns a JSON dictionary containing some of the attributes of |download|. -// The JSON dictionary will also have a field "id" set to |id|, and a field -// "otr" set to |incognito|. -base::DictionaryValue* CreateDownloadItemValue( - content::DownloadItem* download_item, - bool incognito) { - // TODO(asanka): Move towards using download_model here for getting status and - // progress. The difference currently only matters to Drive downloads and - // those don't show up on the downloads page, but should. - DownloadItemModel download_model(download_item); - - // The items which are to be written into file_value are also described in - // chrome/browser/resources/downloads/downloads.js in @typedef for - // BackendDownloadObject. Please update it whenever you add or remove - // any keys in file_value. - base::DictionaryValue* file_value = new base::DictionaryValue(); - - file_value->SetInteger( - "started", static_cast<int>(download_item->GetStartTime().ToTimeT())); - file_value->SetString( - "since_string", ui::TimeFormat::RelativeDate( - download_item->GetStartTime(), NULL)); - - base::Time start_time = download_item->GetStartTime(); - base::string16 date_string = TimeFormatLongDate(start_time); - file_value->SetString("date_string", date_string); - - file_value->SetString("id", base::Uint64ToString(download_item->GetId())); - - base::FilePath download_path(download_item->GetTargetFilePath()); - file_value->Set("file_path", base::CreateFilePathValue(download_path)); - file_value->SetString("file_url", - net::FilePathToFileURL(download_path).spec()); - - extensions::DownloadedByExtension* by_ext = - extensions::DownloadedByExtension::Get(download_item); - std::string by_ext_id; - std::string by_ext_name; - if (by_ext) { - by_ext_id = by_ext->id(); - // TODO(dbeam): why doesn't DownloadsByExtension::name() return a string16? - by_ext_name = by_ext->name(); - - // Lookup the extension's current name() in case the user changed their - // language. This won't work if the extension was uninstalled, so the name - // might be the wrong language. - bool include_disabled = true; - const extensions::Extension* extension = extensions::ExtensionSystem::Get( - Profile::FromBrowserContext(download_item->GetBrowserContext()))-> - extension_service()->GetExtensionById(by_ext->id(), include_disabled); - if (extension) - file_value->SetString("by_ext_name", extension->name()); - } - file_value->SetString("by_ext_id", by_ext_id); - file_value->SetString("by_ext_name", by_ext_name); - - // Keep file names as LTR. - base::string16 file_name = - download_item->GetFileNameToReportUser().LossyDisplayName(); - file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name); - file_value->SetString("file_name", file_name); - file_value->SetString("url", download_item->GetURL().spec()); - file_value->SetBoolean("otr", incognito); - file_value->SetInteger("total", static_cast<int>( - download_item->GetTotalBytes())); - file_value->SetBoolean("file_externally_removed", - download_item->GetFileExternallyRemoved()); - file_value->SetBoolean("resume", download_item->CanResume()); - - const char* danger_type = ""; - base::string16 last_reason_text; - // -2 is invalid, -1 means indeterminate, and 0-100 are in-progress. - int percent = -2; - base::string16 progress_status_text; - bool retry = false; - const char* state = nullptr; - - switch (download_item->GetState()) { - case content::DownloadItem::IN_PROGRESS: { - if (download_item->IsDangerous()) { - state = "DANGEROUS"; - // These are the only danger states that the UI is equipped to handle. - DCHECK(download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE || - download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL || - download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT || - download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT || - download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST || - download_item->GetDangerType() == - content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED); - danger_type = GetDangerTypeString(download_item->GetDangerType()); - } else if (download_item->IsPaused()) { - state = "PAUSED"; - } else { - state = "IN_PROGRESS"; - } - progress_status_text = download_model.GetTabProgressStatusText(); - percent = download_item->PercentComplete(); - break; - } - - case content::DownloadItem::INTERRUPTED: - state = "INTERRUPTED"; - progress_status_text = download_model.GetTabProgressStatusText(); - - if (download_item->CanResume()) - percent = download_item->PercentComplete(); - - last_reason_text = download_model.GetInterruptReasonText(); - if (content::DOWNLOAD_INTERRUPT_REASON_CRASH == - download_item->GetLastReason() && !download_item->CanResume()) { - retry = true; - } - break; - - case content::DownloadItem::CANCELLED: - state = "CANCELLED"; - retry = true; - break; - - case content::DownloadItem::COMPLETE: - DCHECK(!download_item->IsDangerous()); - state = "COMPLETE"; - break; - - case content::DownloadItem::MAX_DOWNLOAD_STATE: - NOTREACHED(); - } - - DCHECK(state); - - file_value->SetString("danger_type", danger_type); - file_value->SetString("last_reason_text", last_reason_text); - file_value->SetInteger("percent", percent); - file_value->SetString("progress_status_text", progress_status_text); - file_value->SetBoolean("retry", retry); - file_value->SetString("state", state); - - return file_value; -} - -// Filters out extension downloads and downloads that don't have a filename yet. -bool IsDownloadDisplayable(const content::DownloadItem& item) { - return !download_crx_util::IsExtensionDownload(item) && - !item.IsTemporary() && - !item.GetFileNameToReportUser().empty() && - !item.GetTargetFilePath().empty() && - DownloadItemModel( - const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf(); -} - } // namespace MdDownloadsDOMHandler::MdDownloadsDOMHandler( - content::DownloadManager* download_manager) - : download_manager_(download_manager), - update_scheduled_(false), + content::DownloadManager* download_manager, content::WebUI* web_ui) + : list_tracker_(download_manager, web_ui), weak_ptr_factory_(this) { // Create our fileicon data source. Profile* profile = Profile::FromBrowserContext( @@ -338,95 +133,19 @@ weak_ptr_factory_.GetWeakPtr())); } -void MdDownloadsDOMHandler::OnDownloadCreated( - content::DownloadManager* manager, content::DownloadItem* download_item) { - if (IsDownloadDisplayable(*download_item)) - ScheduleSendCurrentDownloads(); - else - new_downloads_.insert(download_item->GetId()); -} - -void MdDownloadsDOMHandler::OnDownloadUpdated( - content::DownloadManager* manager, - content::DownloadItem* download_item) { - if (update_scheduled_) - return; - - bool showing_new_item = false; - - if (new_downloads_.count(download_item->GetId())) { - // A new download (that the page doesn't know about yet) has been updated. - if (!IsDownloadDisplayable(*download_item)) { - // Item isn't ready to be displayed yet. Wait until it is. - return; - } - - new_downloads_.erase(download_item->GetId()); - showing_new_item = true; - } - - if (showing_new_item || DownloadItemModel(download_item).IsBeingRevived() || - !IsDownloadDisplayable(*download_item)) { - // A download will be shown or hidden by this update. Resend the list. - ScheduleSendCurrentDownloads(); - return; - } - - if (search_terms_ && !search_terms_->empty()) { - // Don't CallUpdateItem() if download_item doesn't match - // search_terms_. - // TODO(benjhayden): Consider splitting MatchesQuery() out to a function. - content::DownloadManager::DownloadVector all_items, filtered_items; - all_items.push_back(download_item); - DownloadQuery query; - query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_); - query.Search(all_items.begin(), all_items.end(), &filtered_items); - if (filtered_items.empty()) - return; - } - - DCHECK(manager); - scoped_ptr<base::DictionaryValue> item(CreateDownloadItemValue( - download_item, - original_notifier_ && manager == GetMainNotifierManager())); - CallUpdateItem(*item); -} - -void MdDownloadsDOMHandler::OnDownloadRemoved( - content::DownloadManager* manager, - content::DownloadItem* download_item) { - if (!DownloadItemModel(download_item).ShouldShowInShelf()) - return; - - // This relies on |download_item| being removed from DownloadManager in this - // MessageLoop iteration. |download_item| may not have been removed from - // DownloadManager when OnDownloadRemoved() is fired, so bounce off the - // MessageLoop to give it a chance to be removed. SendCurrentDownloads() looks - // at all downloads, and we do not tell it that |download_item| is being - // removed. If DownloadManager is ever changed to not immediately remove - // |download_item| from its map when OnDownloadRemoved is sent, then - // MdDownloadsDOMHandler::OnDownloadRemoved() will need to explicitly tell - // SendCurrentDownloads() that |download_item| was removed. A - // SupportsUserData::Data would be the correct way to do this. - ScheduleSendCurrentDownloads(); +void MdDownloadsDOMHandler::RenderViewReused( + content::RenderViewHost* render_view_host) { + list_tracker_.Stop(); } void MdDownloadsDOMHandler::HandleGetDownloads(const base::ListValue* args) { CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS); - search_terms_.reset(args && !args->empty() ? args->DeepCopy() : NULL); - ScheduleSendCurrentDownloads(); - if (!main_notifier_) { - main_notifier_.reset(new AllDownloadItemNotifier(download_manager_, this)); + bool terms_changed = list_tracker_.SetSearchTerms(*args); + if (terms_changed) + list_tracker_.CallClearAll(); - Profile* profile = Profile::FromBrowserContext( - download_manager_->GetBrowserContext()); - if (profile->IsOffTheRecord()) { - original_notifier_.reset(new AllDownloadItemNotifier( - BrowserContext::GetDownloadManager(profile->GetOriginalProfile()), - this)); - } - } + list_tracker_.Start(); } void MdDownloadsDOMHandler::HandleOpenFile(const base::ListValue* args) { @@ -549,12 +268,17 @@ CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL); + list_tracker_.CallClearAll(); + list_tracker_.Stop(); + DownloadVector downloads; if (GetMainNotifierManager()) GetMainNotifierManager()->GetAllDownloads(&downloads); if (GetOriginalNotifierManager()) GetOriginalNotifierManager()->GetAllDownloads(&downloads); RemoveDownloads(downloads); + + list_tracker_.Start(); } void MdDownloadsDOMHandler::RemoveDownloads(const DownloadVector& to_remove) { @@ -590,29 +314,14 @@ // MdDownloadsDOMHandler, private: -------------------------------------------- -void MdDownloadsDOMHandler::ScheduleSendCurrentDownloads() { - // Don't call SendCurrentDownloads() every time anything changes. Batch them - // together instead. This may handle hundreds of OnDownloadDestroyed() calls - // in a single UI message loop iteration when the user Clears All downloads. - if (update_scheduled_) - return; - - update_scheduled_ = true; - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&MdDownloadsDOMHandler::SendCurrentDownloads, - weak_ptr_factory_.GetWeakPtr())); -} - content::DownloadManager* MdDownloadsDOMHandler::GetMainNotifierManager() const { - return main_notifier_ ? main_notifier_->GetManager() : nullptr; + return list_tracker_.GetMainNotifierManager(); } content::DownloadManager* MdDownloadsDOMHandler::GetOriginalNotifierManager() const { - return original_notifier_ ? original_notifier_->GetManager() : nullptr; + return list_tracker_.GetOriginalNotifierManager(); } void MdDownloadsDOMHandler::FinalizeRemovals() { @@ -628,37 +337,6 @@ } } -void MdDownloadsDOMHandler::SendCurrentDownloads() { - update_scheduled_ = false; - - content::DownloadManager::DownloadVector all_items, filtered_items; - if (GetMainNotifierManager()) { - GetMainNotifierManager()->GetAllDownloads(&all_items); - GetMainNotifierManager()->CheckForHistoryFilesRemoval(); - } - if (GetOriginalNotifierManager()) { - GetOriginalNotifierManager()->GetAllDownloads(&all_items); - GetOriginalNotifierManager()->CheckForHistoryFilesRemoval(); - } - - DownloadQuery query; - if (search_terms_ && !search_terms_->empty()) - query.AddFilter(DownloadQuery::FILTER_QUERY, *search_terms_); - query.AddFilter(base::Bind(&IsDownloadDisplayable)); - query.AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING); - query.Limit(kMaxNumberOfDownloads); - query.Search(all_items.begin(), all_items.end(), &filtered_items); - - base::ListValue results_value; - for (auto* item : filtered_items) { - results_value.Append(CreateDownloadItemValue( - item, - original_notifier_ && GetMainNotifierManager() && - GetMainNotifierManager()->GetDownload(item->GetId()) == item)); - } - CallUpdateAll(results_value); -} - void MdDownloadsDOMHandler::ShowDangerPrompt( content::DownloadItem* dangerous_item) { DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( @@ -722,11 +400,3 @@ content::WebContents* MdDownloadsDOMHandler::GetWebUIWebContents() { return web_ui()->GetWebContents(); } - -void MdDownloadsDOMHandler::CallUpdateAll(const base::ListValue& list) { - web_ui()->CallJavascriptFunction("downloads.Manager.updateAll", list); -} - -void MdDownloadsDOMHandler::CallUpdateItem(const base::DictionaryValue& item) { - web_ui()->CallJavascriptFunction("downloads.Manager.updateItem", item); -}
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h index 0aee5da13..a724d6db 100644 --- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h +++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h
@@ -8,13 +8,10 @@ #include <set> #include <vector> -#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/download/all_download_item_notifier.h" #include "chrome/browser/download/download_danger_prompt.h" -#include "content/public/browser/download_item.h" -#include "content/public/browser/download_manager.h" +#include "chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h" #include "content/public/browser/web_ui_message_handler.h" namespace base { @@ -22,29 +19,25 @@ } namespace content { +class DownloadItem; +class DownloadManager; +class RenderViewHost; class WebContents; +class WebUI; } // The handler for Javascript messages related to the "downloads" view, // also observes changes to the download manager. -class MdDownloadsDOMHandler : public content::WebUIMessageHandler, - public AllDownloadItemNotifier::Observer { +class MdDownloadsDOMHandler : public content::WebUIMessageHandler { public: - explicit MdDownloadsDOMHandler(content::DownloadManager* download_manager); + MdDownloadsDOMHandler(content::DownloadManager* download_manager, + content::WebUI* web_ui); ~MdDownloadsDOMHandler() override; - void Init(); - // WebUIMessageHandler implementation. void RegisterMessages() override; - // AllDownloadItemNotifier::Observer interface - void OnDownloadCreated(content::DownloadManager* manager, - content::DownloadItem* download_item) override; - void OnDownloadUpdated(content::DownloadManager* manager, - content::DownloadItem* download_item) override; - void OnDownloadRemoved(content::DownloadManager* manager, - content::DownloadItem* download_item) override; + void RenderViewReused(content::RenderViewHost* render_view_host); // Callback for the "getDownloads" message. void HandleGetDownloads(const base::ListValue* args); @@ -94,12 +87,6 @@ // depend on WebUI. The other methods that depend on WebUI are // RegisterMessages() and HandleDrag(). virtual content::WebContents* GetWebUIWebContents(); - virtual void CallUpdateAll(const base::ListValue& list); - virtual void CallUpdateItem(const base::DictionaryValue& item); - - // Schedules a call to SendCurrentDownloads() in the next message loop - // iteration. Protected rather than private for use in tests. - void ScheduleSendCurrentDownloads(); // Actually remove downloads with an ID in |removals_|. This cannot be undone. void FinalizeRemovals(); @@ -116,9 +103,6 @@ // null-checking |original_notifier_|. content::DownloadManager* GetOriginalNotifierManager() const; - // Sends the current list of downloads to the page. - void SendCurrentDownloads(); - // Displays a native prompt asking the user for confirmation after accepting // the dangerous download specified by |dangerous|. The function returns // immediately, and will invoke DangerPromptAccepted() asynchronously if the @@ -144,29 +128,11 @@ // Remove all downloads in |to_remove| with the ability to undo removal later. void RemoveDownloads(const DownloadVector& to_remove); - // Weak reference to the DownloadManager this class was constructed with. You - // should probably be using use Get{Main,Original}NotifierManager() instead. - content::DownloadManager* download_manager_; - - // Current search terms. - scoped_ptr<base::ListValue> search_terms_; - - // Notifies OnDownload*() and provides safe access to the DownloadManager. - scoped_ptr<AllDownloadItemNotifier> main_notifier_; - - // If |main_notifier_| observes an incognito profile, then this observes the - // DownloadManager for the original profile; otherwise, this is NULL. - scoped_ptr<AllDownloadItemNotifier> original_notifier_; + DownloadsListTracker list_tracker_; // IDs of downloads to remove when this handler gets deleted. std::vector<IdSet> removals_; - // Whether a call to SendCurrentDownloads() is currently scheduled. - bool update_scheduled_; - - // IDs of new downloads that the page doesn't know about yet. - IdSet new_downloads_; - base::WeakPtrFactory<MdDownloadsDOMHandler> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(MdDownloadsDOMHandler);
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc index 3e8ec98e2..95d3a4e 100644 --- a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc +++ b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.cc
@@ -142,8 +142,8 @@ Profile* profile = Profile::FromWebUI(web_ui); DownloadManager* dlm = BrowserContext::GetDownloadManager(profile); - MdDownloadsDOMHandler* handler = new MdDownloadsDOMHandler(dlm); - web_ui->AddMessageHandler(handler); + handler_ = new MdDownloadsDOMHandler(dlm, web_ui); + web_ui->AddMessageHandler(handler_); // Set up the chrome://downloads/ source. content::WebUIDataSource* source = CreateDownloadsUIHTMLSource(profile); @@ -160,3 +160,8 @@ return ResourceBundle::GetSharedInstance(). LoadDataResourceBytesForScale(IDR_DOWNLOADS_FAVICON, scale_factor); } + +void MdDownloadsUI::RenderViewReused( + content::RenderViewHost* render_view_host) { + handler_->RenderViewReused(render_view_host); +}
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.h b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.h index 37ce107..55d21e1d 100644 --- a/chrome/browser/ui/webui/md_downloads/md_downloads_ui.h +++ b/chrome/browser/ui/webui/md_downloads/md_downloads_ui.h
@@ -13,6 +13,12 @@ class RefCountedMemory; } +namespace content { +class RenderViewHost; +} + +class MdDownloadsDOMHandler; + class MdDownloadsUI : public content::WebUIController { public: explicit MdDownloadsUI(content::WebUI* web_ui); @@ -20,7 +26,12 @@ static base::RefCountedMemory* GetFaviconResourceBytes( ui::ScaleFactor scale_factor); + // content::WebUIController: + void RenderViewReused(content::RenderViewHost* render_view_host) override; + private: + MdDownloadsDOMHandler* handler_; // Weak. + DISALLOW_COPY_AND_ASSIGN(MdDownloadsUI); };
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 9495002..227bec8c 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp
@@ -420,6 +420,7 @@ ], }, { + # GN version: //chrome/tools/crash_service 'target_name': 'crash_service', 'type': 'executable', 'dependencies': [ @@ -488,6 +489,7 @@ }, }, { + # GN version: //chrome/tools/crash_service:crash_service_win64 'target_name': 'crash_service_win64', 'type': 'executable', 'product_name': 'crash_service64',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index bbe8d9996..112ad6d 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -1810,6 +1810,8 @@ 'browser/ui/webui/identity_internals_ui.h', 'browser/ui/webui/inspect_ui.cc', 'browser/ui/webui/inspect_ui.h', + 'browser/ui/webui/md_downloads/downloads_list_tracker.cc', + 'browser/ui/webui/md_downloads/downloads_list_tracher.h', 'browser/ui/webui/md_downloads/md_downloads_dom_handler.cc', 'browser/ui/webui/md_downloads/md_downloads_dom_handler.h', 'browser/ui/webui/md_downloads/md_downloads_ui.cc', @@ -2875,6 +2877,7 @@ '../components/components.gyp:net_log', '../components/components.gyp:page_load_metrics_browser', '../components/components.gyp:translate_content_common', + '../components/components_resources.gyp:components_resources', '../content/app/resources/content_resources.gyp:content_resources', '../media/media.gyp:media', '../net/net.gyp:net_with_v8',
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index 27bd63ee..45274699 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi
@@ -112,6 +112,9 @@ 'dependencies': [ 'kasko_dll', ], + 'sources': [ + 'app/chrome_crash_reporter_client.cc', + ], }], ['win_console_app==1', { 'defines': ['WIN_CONSOLE_APP'],
diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi index 710cee0e..09fccfda 100644 --- a/chrome/chrome_installer_util.gypi +++ b/chrome/chrome_installer_util.gypi
@@ -158,6 +158,8 @@ 'installer/util/product.cc', 'installer/util/product.h', 'installer/util/product_operations.h', + 'installer/util/registry_entry.cc', + 'installer/util/registry_entry.h', 'installer/util/self_cleaning_temp_dir.cc', 'installer/util/self_cleaning_temp_dir.h', 'installer/util/shell_util.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index d0232d4..b5104810 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -1584,6 +1584,7 @@ 'browser/ui/website_settings/permission_menu_model_unittest.cc', 'browser/ui/webui/downloads_util_unittest.cc', 'browser/ui/webui/help/version_updater_chromeos_unittest.cc', + 'browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc', 'browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc', 'browser/ui/webui/options/autofill_options_handler_unittest.cc', 'browser/ui/webui/options/clear_browser_data_handler_unittest.cc',
diff --git a/chrome/common/extensions/api/downloads.idl b/chrome/common/extensions/api/downloads.idl index 9e0f26b..95802fc5 100644 --- a/chrome/common/extensions/api/downloads.idl +++ b/chrome/common/extensions/api/downloads.idl
@@ -55,7 +55,6 @@ NETWORK_INVALID_REQUEST, SERVER_FAILED, SERVER_NO_RANGE, - SERVER_PRECONDITION, SERVER_BAD_CONTENT, SERVER_UNAUTHORIZED, SERVER_CERT_PROBLEM,
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn index d04febf..c205f8c 100644 --- a/chrome/installer/mini_installer/BUILD.gn +++ b/chrome/installer/mini_installer/BUILD.gn
@@ -115,6 +115,16 @@ #'--verbose', ] + deps = [ + "//chrome", + "//chrome:main_dll", + "//chrome/browser/extensions/default_extensions", + "//chrome/installer/setup", + "//third_party/icu:icudata", + + #"../chrome.gyp:chrome_nacl_win64", TODO(GYP) bug 512869. + ] + if (enable_hidpi) { args += [ "--enable_hidpi=1" ] } @@ -145,6 +155,7 @@ "$root_out_dir/natives_blob.bin", "$root_out_dir/snapshot_blob.bin", ] + deps += [ "//v8" ] } depfile = "$target_gen_dir/archive.d" @@ -153,16 +164,6 @@ rebase_path(depfile, root_build_dir), ] - deps = [ - "//chrome", - "//chrome:main_dll", - "//chrome/browser/extensions/default_extensions", - "//chrome/installer/setup", - "//third_party/icu:icudata", - - #"../chrome.gyp:chrome_nacl_win64", TODO(GYP) bug 512869. - ] - if (enable_nacl) { deps += [ "//ppapi/native_client:irt" ] }
diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn index 38d197f6..83759ca 100644 --- a/chrome/installer/util/BUILD.gn +++ b/chrome/installer/util/BUILD.gn
@@ -52,6 +52,8 @@ "product.cc", "product.h", "product_operations.h", + "registry_entry.cc", + "registry_entry.h", "self_cleaning_temp_dir.cc", "self_cleaning_temp_dir.h", "shell_util.cc",
diff --git a/chrome/installer/util/registry_entry.cc b/chrome/installer/util/registry_entry.cc new file mode 100644 index 0000000..6d51b064 --- /dev/null +++ b/chrome/installer/util/registry_entry.cc
@@ -0,0 +1,107 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/registry_entry.h" + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/win/registry.h" +#include "chrome/installer/util/work_item.h" +#include "chrome/installer/util/work_item_list.h" + +RegistryEntry::RegistryEntry(const base::string16& key_path, + const base::string16& value) + : key_path_(key_path), + name_(), + is_string_(true), + value_(value), + int_value_(0), + removal_flag_(RemovalFlag::NONE) {} + +RegistryEntry::RegistryEntry(const base::string16& key_path, + const base::string16& name, + const base::string16& value) + : key_path_(key_path), + name_(name), + is_string_(true), + value_(value), + int_value_(0), + removal_flag_(RemovalFlag::NONE) {} + +RegistryEntry::RegistryEntry(const base::string16& key_path, + const base::string16& name, + DWORD value) + : key_path_(key_path), + name_(name), + is_string_(false), + value_(), + int_value_(value), + removal_flag_(RemovalFlag::NONE) {} + +void RegistryEntry::AddToWorkItemList(HKEY root, WorkItemList* items) const { + if (removal_flag_ == RemovalFlag::VALUE) { + items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, + name_); + } else if (removal_flag_ == RemovalFlag::KEY) { + items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); + } else { + DCHECK(removal_flag_ == RemovalFlag::NONE); + items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); + if (is_string_) { + items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, + name_, value_, true); + } else { + items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, + name_, int_value_, true); + } + } +} + +bool RegistryEntry::ExistsInRegistry(uint32 look_for_in) const { + DCHECK(look_for_in); + + RegistryStatus status = DOES_NOT_EXIST; + if (look_for_in & LOOK_IN_HKCU) + status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); + if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) + status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); + return status == SAME_VALUE; +} + +bool RegistryEntry::KeyExistsInRegistry(uint32 look_for_in) const { + DCHECK(look_for_in); + + RegistryStatus status = DOES_NOT_EXIST; + if (look_for_in & LOOK_IN_HKCU) + status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); + if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) + status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); + return status != DOES_NOT_EXIST; +} + +RegistryEntry::RegistryStatus RegistryEntry::StatusInRegistryUnderRoot( + HKEY root) const { + base::win::RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); + bool found = false; + bool correct_value = false; + if (is_string_) { + base::string16 read_value; + found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; + if (found) { + correct_value = + read_value.size() == value_.size() && + ::CompareString( + LOCALE_USER_DEFAULT, NORM_IGNORECASE, read_value.data(), + base::saturated_cast<int>(read_value.size()), value_.data(), + base::saturated_cast<int>(value_.size())) == CSTR_EQUAL; + } + } else { + DWORD read_value; + found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS; + if (found) + correct_value = read_value == int_value_; + } + return found ? (correct_value ? SAME_VALUE : DIFFERENT_VALUE) + : DOES_NOT_EXIST; +}
diff --git a/chrome/installer/util/registry_entry.h b/chrome/installer/util/registry_entry.h new file mode 100644 index 0000000..90717ee --- /dev/null +++ b/chrome/installer/util/registry_entry.h
@@ -0,0 +1,120 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_REGISTRY_ENTRY_H_ +#define CHROME_INSTALLER_UTIL_REGISTRY_ENTRY_H_ + +#include <windows.h> + +#include "base/macros.h" +#include "base/strings/string16.h" + +class WorkItemList; + +// This class represents a single registry entry (a key and its value). A +// collection of registry entries should be collected into a list and written +// transactionally using a WorkItemList. This is preferred to writing to the +// registry directly, because if anything goes wrong, they can be rolled back. +class RegistryEntry { + public: + // A bit-field enum of places to look for this key in the Windows registry. + enum LookForIn { + LOOK_IN_HKCU = 1 << 0, + LOOK_IN_HKLM = 1 << 1, + LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, + }; + + // Identifies the type of removal this RegistryEntry is flagged for, if any. + enum class RemovalFlag { + // Default case: install the key/value. + NONE, + // Registry value under |key_path_|\|name_| is flagged for deletion. + VALUE, + // Registry key under |key_path_| is flag for deletion. + KEY, + }; + + // Create an object that represent default value of a key. + RegistryEntry(const base::string16& key_path, const base::string16& value); + + // Create an object that represent a key of type REG_SZ. + RegistryEntry(const base::string16& key_path, + const base::string16& name, + const base::string16& value); + + // Create an object that represent a key of integer type. + RegistryEntry(const base::string16& key_path, + const base::string16& name, + DWORD value); + + // Flags this RegistryKey with |removal_flag|, indicating that it should be + // removed rather than created. Note that this will not result in cleaning up + // the entire registry hierarchy below RegistryEntry even if it is left empty + // by this operation (this should thus not be used for uninstall, but only to + // unregister keys that should explicitly no longer be active in the current + // configuration). + void set_removal_flag(RemovalFlag removal_flag) { + removal_flag_ = removal_flag; + } + + // Generates work_item tasks required to create (or potentially delete based + // on |removal_flag_|) the current RegistryEntry and add them to the given + // work item list. + void AddToWorkItemList(HKEY root, WorkItemList* items) const; + + // Returns true if this key is flagged for removal. + bool IsFlaggedForRemoval() const { + return removal_flag_ != RemovalFlag::NONE; + } + + // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| + // and value is |value_|. If the key does NOT exist in HKCU, checks for + // the correct name and value in HKLM. + // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the + // key, unspecified roots are not looked into (i.e. the the key is assumed not + // to exist in them). + // |look_for_in| must at least specify one root to look into. + // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' + // behavior when searching in HKCR (HKCU takes precedence over HKLM). For + // registrations outside of HKCR on versions of Windows prior to Win8, + // Chrome's values go in HKLM. This function will make unnecessary (but + // harmless) queries into HKCU in that case. + bool ExistsInRegistry(uint32 look_for_in) const; + + // Checks if the current registry entry exists in \|key_path_|\|name_|, + // regardless of value. Same lookup rules as ExistsInRegistry. + // Unlike ExistsInRegistry, this returns true if some other value is present + // with the same key. + bool KeyExistsInRegistry(uint32 look_for_in) const; + + private: + // States this RegistryKey can be in compared to the registry. + enum RegistryStatus { + // |name_| does not exist in the registry + DOES_NOT_EXIST, + // |name_| exists, but its value != |value_| + DIFFERENT_VALUE, + // |name_| exists and its value is |value_| + SAME_VALUE, + }; + + base::string16 key_path_; // key path for the registry entry + base::string16 name_; // name of the registry entry + bool is_string_; // true if current registry entry is of type REG_SZ + base::string16 value_; // string value (useful if is_string_ = true) + DWORD int_value_; // integer value (useful if is_string_ = false) + + // Identifies whether this RegistryEntry is flagged for removal (i.e. no + // longer relevant on the configuration it was created under). + RemovalFlag removal_flag_; + + // Helper function for ExistsInRegistry(). + // Returns the RegistryStatus of the current registry entry in + // |root|\|key_path_|\|name_|. + RegistryStatus StatusInRegistryUnderRoot(HKEY root) const; + + DISALLOW_COPY_AND_ASSIGN(RegistryEntry); +}; + +#endif // CHROME_INSTALLER_UTIL_REGISTRY_ENTRY_H_
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index 655fa62..1174117 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc
@@ -51,6 +51,7 @@ #include "chrome/installer/util/l10n_string_util.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/registry_entry.h" #include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/work_item.h" @@ -188,207 +189,6 @@ base::string16 delegate_clsid; }; -// This class represents a single registry entry (a key and its value). A -// collection of registry entries should be collected into a list and written -// transactionally using a WorkItemList. This is preferred to writing to the -// registry directly, because if anything goes wrong, they can be rolled back. -class RegistryEntry { - public: - // A bit-field enum of places to look for this key in the Windows registry. - enum LookForIn { - LOOK_IN_HKCU = 1 << 0, - LOOK_IN_HKLM = 1 << 1, - LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, - }; - - // Identifies the type of removal this RegistryEntry is flagged for, if any. - enum class RemovalFlag { - // Default case: install the key/value. - NONE, - // Registry value under |key_path_|\|name_| is flagged for deletion. - VALUE, - // Registry key under |key_path_| is flag for deletion. - KEY, - }; - - // Create an object that represent default value of a key. - RegistryEntry(const base::string16& key_path, const base::string16& value); - - // Create an object that represent a key of type REG_SZ. - RegistryEntry(const base::string16& key_path, - const base::string16& name, - const base::string16& value); - - // Create an object that represent a key of integer type. - RegistryEntry(const base::string16& key_path, - const base::string16& name, - DWORD value); - - // Flags this RegistryKey with |removal_flag|, indicating that it should be - // removed rather than created. Note that this will not result in cleaning up - // the entire registry hierarchy below RegistryEntry even if it is left empty - // by this operation (this should thus not be used for uninstall, but only to - // unregister keys that should explicitly no longer be active in the current - // configuration). - void set_removal_flag(RemovalFlag removal_flag) { - removal_flag_ = removal_flag; - } - - // Generates work_item tasks required to create (or potentially delete based - // on |removal_flag_|) the current RegistryEntry and add them to the given - // work item list. - void AddToWorkItemList(HKEY root, WorkItemList* items) const; - - // Returns true if this key is flagged for removal. - bool IsFlaggedForRemoval() const { - return removal_flag_ != RemovalFlag::NONE; - } - - // Checks if the current registry entry exists in HKCU\|key_path_|\|name_| - // and value is |value_|. If the key does NOT exist in HKCU, checks for - // the correct name and value in HKLM. - // |look_for_in| specifies roots (HKCU and/or HKLM) in which to look for the - // key, unspecified roots are not looked into (i.e. the the key is assumed not - // to exist in them). - // |look_for_in| must at least specify one root to look into. - // If |look_for_in| is LOOK_IN_HKCU_THEN_HKLM, this method mimics Windows' - // behavior when searching in HKCR (HKCU takes precedence over HKLM). For - // registrations outside of HKCR on versions of Windows prior to Win8, - // Chrome's values go in HKLM. This function will make unnecessary (but - // harmless) queries into HKCU in that case. - bool ExistsInRegistry(uint32 look_for_in) const; - - // Checks if the current registry entry exists in \|key_path_|\|name_|, - // regardless of value. Same lookup rules as ExistsInRegistry. - // Unlike ExistsInRegistry, this returns true if some other value is present - // with the same key. - bool KeyExistsInRegistry(uint32 look_for_in) const; - - private: - // States this RegistryKey can be in compared to the registry. - enum RegistryStatus { - // |name_| does not exist in the registry - DOES_NOT_EXIST, - // |name_| exists, but its value != |value_| - DIFFERENT_VALUE, - // |name_| exists and its value is |value_| - SAME_VALUE, - }; - - base::string16 key_path_; // key path for the registry entry - base::string16 name_; // name of the registry entry - bool is_string_; // true if current registry entry is of type REG_SZ - base::string16 value_; // string value (useful if is_string_ = true) - DWORD int_value_; // integer value (useful if is_string_ = false) - - // Identifies whether this RegistryEntry is flagged for removal (i.e. no - // longer relevant on the configuration it was created under). - RemovalFlag removal_flag_; - - // Helper function for ExistsInRegistry(). - // Returns the RegistryStatus of the current registry entry in - // |root|\|key_path_|\|name_|. - RegistryStatus StatusInRegistryUnderRoot(HKEY root) const; - - DISALLOW_COPY_AND_ASSIGN(RegistryEntry); -}; // class RegistryEntry - -RegistryEntry::RegistryEntry(const base::string16& key_path, - const base::string16& value) - : key_path_(key_path), - name_(), - is_string_(true), - value_(value), - int_value_(0), - removal_flag_(RemovalFlag::NONE) {} - -RegistryEntry::RegistryEntry(const base::string16& key_path, - const base::string16& name, - const base::string16& value) - : key_path_(key_path), - name_(name), - is_string_(true), - value_(value), - int_value_(0), - removal_flag_(RemovalFlag::NONE) {} - -RegistryEntry::RegistryEntry(const base::string16& key_path, - const base::string16& name, - DWORD value) - : key_path_(key_path), - name_(name), - is_string_(false), - value_(), - int_value_(value), - removal_flag_(RemovalFlag::NONE) {} - -void RegistryEntry::AddToWorkItemList(HKEY root, WorkItemList* items) const { - if (removal_flag_ == RemovalFlag::VALUE) { - items->AddDeleteRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, - name_); - } else if (removal_flag_ == RemovalFlag::KEY) { - items->AddDeleteRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); - } else { - DCHECK(removal_flag_ == RemovalFlag::NONE); - items->AddCreateRegKeyWorkItem(root, key_path_, WorkItem::kWow64Default); - if (is_string_) { - items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, - name_, value_, true); - } else { - items->AddSetRegValueWorkItem(root, key_path_, WorkItem::kWow64Default, - name_, int_value_, true); - } - } -} - -bool RegistryEntry::ExistsInRegistry(uint32 look_for_in) const { - DCHECK(look_for_in); - - RegistryStatus status = DOES_NOT_EXIST; - if (look_for_in & LOOK_IN_HKCU) - status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); - if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) - status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); - return status == SAME_VALUE; -} - -bool RegistryEntry::KeyExistsInRegistry(uint32 look_for_in) const { - DCHECK(look_for_in); - - RegistryStatus status = DOES_NOT_EXIST; - if (look_for_in & LOOK_IN_HKCU) - status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); - if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) - status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); - return status != DOES_NOT_EXIST; -} - -RegistryEntry::RegistryStatus RegistryEntry::StatusInRegistryUnderRoot( - HKEY root) const { - RegKey key(root, key_path_.c_str(), KEY_QUERY_VALUE); - bool found = false; - bool correct_value = false; - if (is_string_) { - base::string16 read_value; - found = key.ReadValue(name_.c_str(), &read_value) == ERROR_SUCCESS; - if (found) { - correct_value = - read_value.size() == value_.size() && - ::CompareString( - LOCALE_USER_DEFAULT, NORM_IGNORECASE, read_value.data(), - base::saturated_cast<int>(read_value.size()), value_.data(), - base::saturated_cast<int>(value_.size())) == CSTR_EQUAL; - } - } else { - DWORD read_value; - found = key.ReadValueDW(name_.c_str(), &read_value) == ERROR_SUCCESS; - if (found) - correct_value = read_value == int_value_; - } - return found ? (correct_value ? SAME_VALUE : DIFFERENT_VALUE) - : DOES_NOT_EXIST; -} - // Returns the Windows browser client registration key for Chrome. For example: // "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly speaking, we // should use the name of the executable (e.g., "chrome.exe"), but that ship has
diff --git a/chrome/renderer/instant_restricted_id_cache_unittest.cc b/chrome/renderer/instant_restricted_id_cache_unittest.cc index e8447ec1..ea06a226 100644 --- a/chrome/renderer/instant_restricted_id_cache_unittest.cc +++ b/chrome/renderer/instant_restricted_id_cache_unittest.cc
@@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <stdint.h> + +#include <limits> #include <string> #include <utility> #include <vector> @@ -199,11 +202,12 @@ // Check first addition. std::vector<ItemIDPair> input1; input1.push_back(std::make_pair(0, TestData("A"))); - input1.push_back(std::make_pair(kint32max, TestData("B"))); + input1.push_back( + std::make_pair(std::numeric_limits<int32_t>::max(), TestData("B"))); input1.push_back(std::make_pair(-100, TestData("C"))); cache.AddItemsWithRestrictedID(input1); EXPECT_EQ(3u, cache.cache_.size()); - EXPECT_EQ(kint32max, cache.last_restricted_id_); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), cache.last_restricted_id_); std::vector<ItemIDPair> output; cache.GetCurrentItems(&output); @@ -215,18 +219,20 @@ TestData t; EXPECT_FALSE(cache.GetItemWithRestrictedID(1, &t)); - EXPECT_TRUE(cache.GetItemWithRestrictedID(kint32max, &t)); + EXPECT_TRUE( + cache.GetItemWithRestrictedID(std::numeric_limits<int32_t>::max(), &t)); EXPECT_EQ(input1[1].second, t); EXPECT_TRUE(cache.GetItemWithRestrictedID(-100, &t)); EXPECT_EQ(input1[2].second, t); // Add more items, one with same rid, no overflow. std::vector<ItemIDPair> input2; - input2.push_back(std::make_pair(kint32min, TestData("D"))); + input2.push_back( + std::make_pair(std::numeric_limits<int32_t>::min(), TestData("D"))); input2.push_back(std::make_pair(7, TestData("E"))); cache.AddItemsWithRestrictedID(input2); EXPECT_EQ(4u, cache.cache_.size()); - EXPECT_EQ(kint32max, cache.last_restricted_id_); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), cache.last_restricted_id_); output.clear(); cache.GetCurrentItems(&output); @@ -237,9 +243,11 @@ } EXPECT_FALSE(cache.GetItemWithRestrictedID(0, &t)); - EXPECT_TRUE(cache.GetItemWithRestrictedID(kint32max, &t)); + EXPECT_TRUE( + cache.GetItemWithRestrictedID(std::numeric_limits<int32_t>::max(), &t)); EXPECT_EQ(input1[1].second, t); - EXPECT_TRUE(cache.GetItemWithRestrictedID(kint32min, &t)); + EXPECT_TRUE( + cache.GetItemWithRestrictedID(std::numeric_limits<int32_t>::min(), &t)); EXPECT_EQ(input2[0].second, t); EXPECT_TRUE(cache.GetItemWithRestrictedID(7, &t)); EXPECT_EQ(input2[1].second, t); @@ -250,17 +258,18 @@ input3.push_back(TestData("G")); cache.AddItems(input3); EXPECT_EQ(4u, cache.cache_.size()); - EXPECT_EQ(kint32min + 1, cache.last_restricted_id_); + EXPECT_EQ(std::numeric_limits<int32_t>::min() + 1, cache.last_restricted_id_); output.clear(); cache.GetCurrentItems(&output); EXPECT_EQ(2u, output.size()); for (int i = 0; i < 2; ++i) { - EXPECT_EQ(kint32min + i, output[i].first); + EXPECT_EQ(std::numeric_limits<int32_t>::min() + i, output[i].first); EXPECT_EQ(input3[i], output[i].second); } - EXPECT_TRUE(cache.GetItemWithRestrictedID(kint32min, &t)); + EXPECT_TRUE( + cache.GetItemWithRestrictedID(std::numeric_limits<int32_t>::min(), &t)); EXPECT_EQ(input3[0], t); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index cfefd99..32a0caaa 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1613,7 +1613,6 @@ if (!is_ios) { deps += [ - ":unit_tests_js", "//components/autofill/content/browser/wallet:test_support", "//components/autofill/content/renderer:test_support", "//components/data_reduction_proxy/core/browser:test_support", @@ -1669,6 +1668,7 @@ } if (!is_android && !is_ios) { + deps += [ ":unit_tests_js" ] sources += rebase_path( chrome_tests_unit_gypi_values.chrome_unit_tests_non_mobile_sources, ".",
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index ebe7386..51d6ead9 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -62,13 +62,6 @@ void Maximize() override {} void Minimize() override {} void Restore() override {} - void EnterFullscreen(const GURL& url, - ExclusiveAccessBubbleType type, - bool with_toolbar) override {} - void ExitFullscreen() override {} - void UpdateExclusiveAccessExitBubbleContent( - const GURL& url, - ExclusiveAccessBubbleType bubble_type) override {} bool ShouldHideUIForFullscreen() const override; bool IsFullscreen() const override; bool IsFullscreenBubbleVisible() const override;
diff --git a/chrome/test/data/safe_browsing/mach_o/Makefile b/chrome/test/data/safe_browsing/mach_o/Makefile index 7b11582..199685b 100644 --- a/chrome/test/data/safe_browsing/mach_o/Makefile +++ b/chrome/test/data/safe_browsing/mach_o/Makefile
@@ -72,6 +72,12 @@ .PHONY: modified-bundle.app modified-bundle.app: test-bundle.app lib32.dylib executable64 ditto $< $@ + echo "<xml/>" > $@/Contents/Resources/Base.lproj/InfoPlist.strings + security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ + $(PWD)/codesign.keychain + codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ + $@ --all-architectures --resource-rules ResourceRules + echo "BAD" > $@/Contents/Resources/Base.lproj/InfoPlist.strings touch $@/Contents/Resources/codesign.cfg ditto $(word 2,$^) $@/Contents/Frameworks/libsigned64.dylib ditto $(word 3,$^) $@/Contents/Resources/executable32 @@ -101,3 +107,13 @@ ditto $< $@ printf '\x31' | dd bs=1 seek=24448 count=1 conv=notrunc \ of=$@/Contents/MacOS/test-bundle + +.PHONY: modified-localization.app +modified-localization.app: test-bundle.app + ditto $< $@ + echo "<xml/>" > $@/Contents/Resources/Base.lproj/InfoPlist.strings + security unlock-keychain -p $(KEYCHAIN_PASSWORD) \ + $(PWD)/codesign.keychain + codesign -f -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \ + $@ --all-architectures --resource-rules ResourceRules + echo "CORRUPT" > $@/Contents/Resources/Base.lproj/InfoPlist.strings
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/Frameworks/libsigned64.dylib b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/Frameworks/libsigned64.dylib old mode 100644 new mode 100755 Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/MacOS/test-bundle b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/MacOS/test-bundle index 4acc277..fe2c6b3 100644 --- a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/MacOS/test-bundle +++ b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/MacOS/test-bundle Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/Resources/Base.lproj/InfoPlist.strings b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/Resources/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000..7b3a785 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/Resources/Base.lproj/InfoPlist.strings
@@ -0,0 +1 @@ +BAD
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/_CodeSignature/CodeResources b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/_CodeSignature/CodeResources index aa06c23..fd75581 100644 --- a/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/_CodeSignature/CodeResources +++ b/chrome/test/data/safe_browsing/mach_o/modified-bundle.app/Contents/_CodeSignature/CodeResources
@@ -8,6 +8,15 @@ <data> eD0Asf8/OXa6v2aNFp33nh5bsGw= </data> + <key>Resources/Base.lproj/InfoPlist.strings</key> + <dict> + <key>hash</key> + <data> + VPj12JOfhf20Glf0iP7cnVZnGeQ= + </data> + <key>optional</key> + <true/> + </dict> <key>Resources/Base.lproj/MainMenu.nib</key> <dict> <key>hash</key> @@ -28,6 +37,15 @@ <data> eD0Asf8/OXa6v2aNFp33nh5bsGw= </data> + <key>Resources/Base.lproj/InfoPlist.strings</key> + <dict> + <key>hash</key> + <data> + VPj12JOfhf20Glf0iP7cnVZnGeQ= + </data> + <key>optional</key> + <true/> + </dict> <key>Resources/Base.lproj/MainMenu.nib</key> <dict> <key>hash</key>
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Frameworks/libsigned64.dylib b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Frameworks/libsigned64.dylib new file mode 100644 index 0000000..77b77db --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Frameworks/libsigned64.dylib Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Info.plist b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Info.plist new file mode 100644 index 0000000..a6082b8 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Info.plist
@@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>BuildMachineOSBuild</key> + <string>14F27</string> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>test-bundle</string> + <key>CFBundleIdentifier</key> + <string>google-test.test-bundle</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>test-bundle</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>DTCompiler</key> + <string>com.apple.compilers.llvm.clang.1_0</string> + <key>DTPlatformBuild</key> + <string>6D2105</string> + <key>DTPlatformVersion</key> + <string>GM</string> + <key>DTSDKBuild</key> + <string>14D125</string> + <key>DTSDKName</key> + <string>macosx10.10</string> + <key>DTXcode</key> + <string>0632</string> + <key>DTXcodeBuild</key> + <string>6D2105</string> + <key>LSMinimumSystemVersion</key> + <string>10.10</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2015 test-bundle. All rights reserved.</string> + <key>NSMainNibFile</key> + <string>MainMenu</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> +</dict> +</plist>
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/MacOS/test-bundle b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/MacOS/test-bundle new file mode 100644 index 0000000..8429f6f4 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/MacOS/test-bundle Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/PkgInfo b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/PkgInfo new file mode 100644 index 0000000..bd04210 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/PkgInfo
@@ -0,0 +1 @@ +APPL???? \ No newline at end of file
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/InfoPlist.strings b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000..ad9fa81 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/InfoPlist.strings
@@ -0,0 +1 @@ +CORRUPT
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/MainMenu.nib b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/MainMenu.nib new file mode 100644 index 0000000..483099c7 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/Base.lproj/MainMenu.nib Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/executable32 b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/executable32 new file mode 100644 index 0000000..9337b20 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/Resources/executable32 Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/_CodeSignature/CodeResources b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/_CodeSignature/CodeResources new file mode 100644 index 0000000..fd75581 --- /dev/null +++ b/chrome/test/data/safe_browsing/mach_o/modified-localization.app/Contents/_CodeSignature/CodeResources
@@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>files</key> + <dict> + <key>Frameworks/libsigned64.dylib</key> + <data> + eD0Asf8/OXa6v2aNFp33nh5bsGw= + </data> + <key>Resources/Base.lproj/InfoPlist.strings</key> + <dict> + <key>hash</key> + <data> + VPj12JOfhf20Glf0iP7cnVZnGeQ= + </data> + <key>optional</key> + <true/> + </dict> + <key>Resources/Base.lproj/MainMenu.nib</key> + <dict> + <key>hash</key> + <data> + 36VmRur+3AKfYrTxgwnd4cqqjvY= + </data> + <key>optional</key> + <true/> + </dict> + <key>Resources/executable32</key> + <data> + 8UYv2Wx4Y+rmOojWWLGJj+o5iqU= + </data> + </dict> + <key>files2</key> + <dict> + <key>Frameworks/libsigned64.dylib</key> + <data> + eD0Asf8/OXa6v2aNFp33nh5bsGw= + </data> + <key>Resources/Base.lproj/InfoPlist.strings</key> + <dict> + <key>hash</key> + <data> + VPj12JOfhf20Glf0iP7cnVZnGeQ= + </data> + <key>optional</key> + <true/> + </dict> + <key>Resources/Base.lproj/MainMenu.nib</key> + <dict> + <key>hash</key> + <data> + 36VmRur+3AKfYrTxgwnd4cqqjvY= + </data> + <key>optional</key> + <true/> + </dict> + <key>Resources/executable32</key> + <data> + 8UYv2Wx4Y+rmOojWWLGJj+o5iqU= + </data> + </dict> + <key>rules</key> + <dict> + <key>^Frameworks</key> + <true/> + <key>^Resources/</key> + <true/> + <key>^Resources/.*\.lproj/</key> + <dict> + <key>optional</key> + <true/> + <key>weight</key> + <real>1000</real> + </dict> + <key>^Resources/.*\.lproj/locversion.plist$</key> + <dict> + <key>omit</key> + <true/> + <key>weight</key> + <real>1100</real> + </dict> + <key>^version.plist$</key> + <true/> + </dict> + <key>rules2</key> + <dict> + <key>.*\.dSYM($|/)</key> + <dict> + <key>weight</key> + <real>11</real> + </dict> + <key>^(.*/)?\.DS_Store$</key> + <dict> + <key>omit</key> + <true/> + <key>weight</key> + <real>2000</real> + </dict> + <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key> + <dict> + <key>weight</key> + <real>10</real> + </dict> + <key>^.*</key> + <true/> + <key>^Info\.plist$</key> + <dict> + <key>omit</key> + <true/> + <key>weight</key> + <real>20</real> + </dict> + <key>^PkgInfo$</key> + <dict> + <key>omit</key> + <true/> + <key>weight</key> + <real>20</real> + </dict> + <key>^Resources/</key> + <dict> + <key>weight</key> + <real>20</real> + </dict> + <key>^Resources/.*\.lproj/</key> + <dict> + <key>optional</key> + <true/> + <key>weight</key> + <real>1000</real> + </dict> + <key>^Resources/.*\.lproj/locversion.plist$</key> + <dict> + <key>omit</key> + <true/> + <key>weight</key> + <real>1100</real> + </dict> + <key>^[^/]+$</key> + <dict> + <key>weight</key> + <real>10</real> + </dict> + <key>^embedded\.provisionprofile$</key> + <dict> + <key>weight</key> + <real>20</real> + </dict> + <key>^version\.plist$</key> + <dict> + <key>weight</key> + <real>20</real> + </dict> + </dict> +</dict> +</plist>
diff --git a/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/Frameworks/libsigned64.dylib b/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/Frameworks/libsigned64.dylib old mode 100644 new mode 100755 Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/MacOS/test-bundle b/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/MacOS/test-bundle index 4acc277..696cf73bb 100644 --- a/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/MacOS/test-bundle +++ b/chrome/test/data/safe_browsing/mach_o/test-bundle.app/Contents/MacOS/test-bundle Binary files differ
diff --git a/chrome/test/data/webui/md_downloads/layout_tests.js b/chrome/test/data/webui/md_downloads/layout_tests.js index 7c09cf6..e319b582 100644 --- a/chrome/test/data/webui/md_downloads/layout_tests.js +++ b/chrome/test/data/webui/md_downloads/layout_tests.js
@@ -12,13 +12,14 @@ PolymerTest.clearBody(); manager = document.createElement('downloads-manager'); document.body.appendChild(manager); + assertEquals(manager, downloads.Manager.get()); }); test('long URLs ellide', function() { - manager.updateAll_([{ + downloads.Manager.insertItems(0, [{ file_name: 'file name', state: downloads.States.COMPLETE, - url: 'a'.repeat(10000), + url: 'a'.repeat(1000), }]); Polymer.dom.flush();
diff --git a/chrome/test/data/webui/settings/checkbox_tests.js b/chrome/test/data/webui/settings/checkbox_tests.js index 88b0e5f..1e63e68 100644 --- a/chrome/test/data/webui/settings/checkbox_tests.js +++ b/chrome/test/data/webui/settings/checkbox_tests.js
@@ -66,6 +66,25 @@ assertFalse(testElement.checked); assertFalse(testElement.$.checkbox.checked); }); + + test('numerical pref', function() { + var prefNum = { + key: 'test', + type: chrome.settingsPrivate.PrefType.NUMBER, + value: 1 + }; + + testElement.set('pref', prefNum); + assertTrue(testElement.checked); + + testElement.removeAttribute('checked'); + assertFalse(testElement.checked); + assertEquals(0, prefNum.value); + + testElement.setAttribute('checked', ''); + assertTrue(testElement.checked); + assertEquals(1, prefNum.value); + }); }); }
diff --git a/chrome/tools/crash_service/BUILD.gn b/chrome/tools/crash_service/BUILD.gn new file mode 100644 index 0000000..287909b --- /dev/null +++ b/chrome/tools/crash_service/BUILD.gn
@@ -0,0 +1,43 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_win) + +executable("crash_service") { + sources = [ + "main.cc", + ] + + configs -= [ "//build/config/win:console" ] + configs += [ "//build/config/win:windowed" ] + + deps = [ + "//base", + "//chrome/common:constants", + "//chrome/installer/util", + "//components/crash/content/tools:crash_service", + "//content/public/common:static_switches", + ] +} + +if (target_cpu == "x86" && current_cpu == "x86") { + # Cross-compile a 64-bit version when compiling a 64-bit target. + copy("crash_service_win64") { + crash_service_64_target = ":crash_service(//build/toolchain/win:x64)" + + sources = [ + # It would be nice if get_target_outputs would work on the executable, + # but instead we have to manually compute the executable name. + get_label_info(crash_service_64_target, "root_out_dir") + + "/crash_service.exe", + ] + outputs = [ + "$root_build_dir/crash_service_win64.exe", + ] + + deps = [ + crash_service_64_target, + ] + } +}
diff --git a/chrome_elf/BUILD.gn b/chrome_elf/BUILD.gn index 4f9c7474..3afa19b 100644 --- a/chrome_elf/BUILD.gn +++ b/chrome_elf/BUILD.gn
@@ -106,12 +106,9 @@ "blacklist/blacklist_interceptions.h", ] deps = [ - # Depend on base_static, but do NOT take a dependency on base.gyp:base - # as that would risk pulling in base's link-time dependencies which - # chrome_elf cannot do. ":breakpad", ":constants", - "//base:base_static", + "//base", "//sandbox:sandbox", ] }
diff --git a/chrome_elf/blacklist.gypi b/chrome_elf/blacklist.gypi index 50d1a26..f552186 100644 --- a/chrome_elf/blacklist.gypi +++ b/chrome_elf/blacklist.gypi
@@ -17,10 +17,7 @@ 'blacklist/blacklist_interceptions.h', ], 'dependencies': [ - # Depend on base_static, but do NOT take a dependency on base.gyp:base - # as that would risk pulling in base's link-time dependencies which - # chrome_elf cannot do. - '../base/base.gyp:base_static', + '../base/base.gyp:base', '../chrome_elf/chrome_elf.gyp:chrome_elf_breakpad', '../chrome_elf/chrome_elf.gyp:chrome_elf_constants', '../sandbox/sandbox.gyp:sandbox',
diff --git a/chrome_elf/elf_imports_unittest.cc b/chrome_elf/elf_imports_unittest.cc index 941c641..87a1f59 100644 --- a/chrome_elf/elf_imports_unittest.cc +++ b/chrome_elf/elf_imports_unittest.cc
@@ -47,20 +47,35 @@ } }; +// Run this test only in Release builds. +// +// This test makes sure that chrome_elf.dll has only certain types of imports. +// However, it directly and indirectly depends on base, which has lots more +// imports than are allowed here. +// +// In release builds, the offending imports are all stripped since this +// depends on a relatively small portion of base. In GYP, this works in debug +// builds as well because static libraries are used for the sandbox and base +// targets and the files that use e.g. user32.dll happen to not get brought +// into the build in the first place (due to the way static libraries are +// linked where only the required .o files are included). But we don't bother +// differentiating GYP and GN builds for this purpose. +// +// If you break this test, you may have changed base or the Windows sandbox +// such that more system imports are required to link. +#ifdef NDEBUG TEST_F(ELFImportsTest, ChromeElfSanityCheck) { - std::vector<std::string> elf_imports; - base::FilePath dll; ASSERT_TRUE(PathService::Get(base::DIR_EXE, &dll)); dll = dll.Append(L"chrome_elf.dll"); + + std::vector<std::string> elf_imports; GetImports(dll, &elf_imports); // Check that ELF has imports. ASSERT_LT(0u, elf_imports.size()) << "Ensure the chrome_elf_unittests " "target was built, instead of chrome_elf_unittests.exe"; - std::vector<std::string>::iterator it(elf_imports.begin()); - static const char* const kValidFilePatterns[] = { "KERNEL32.dll", "MSVC*", @@ -74,15 +89,18 @@ }; // Make sure all of ELF's imports are in the valid imports list. - for (; it != elf_imports.end(); it++) { + for (const std::string& import : elf_imports) { bool match = false; for (int i = 0; i < arraysize(kValidFilePatterns); ++i) { - if (base::MatchPattern(*it, kValidFilePatterns[i])) + if (base::MatchPattern(import, kValidFilePatterns[i])) { match = true; + break; + } } - ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll: " << *it; + ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll: " << import; } } +#endif // NDEBUG TEST_F(ELFImportsTest, ChromeExeSanityCheck) { std::vector<std::string> exe_imports;
diff --git a/chromecast/media/cma/decoder/BUILD.gn b/chromecast/media/cma/decoder/BUILD.gn new file mode 100644 index 0000000..5adf546 --- /dev/null +++ b/chromecast/media/cma/decoder/BUILD.gn
@@ -0,0 +1,18 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("decoder") { + sources = [ + "cast_audio_decoder.h", + "cast_audio_decoder_android.cc", + "cast_audio_decoder_linux.cc", + ] + + deps = [ + "//base", + "//chromecast/media/cma/base", + "//media", + "//media:shared_memory_support", + ] +}
diff --git a/chromecast/media/cma/decoder/DEPS b/chromecast/media/cma/decoder/DEPS new file mode 100644 index 0000000..343deac4 --- /dev/null +++ b/chromecast/media/cma/decoder/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+chromecast/media/cma/base", + "+media/filters", +]
diff --git a/chromecast/media/cma/decoder/cast_audio_decoder.h b/chromecast/media/cma/decoder/cast_audio_decoder.h new file mode 100644 index 0000000..23f4e8c --- /dev/null +++ b/chromecast/media/cma/decoder/cast_audio_decoder.h
@@ -0,0 +1,76 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_MEDIA_CMA_DECODER_CAST_AUDIO_DECODER_H_ +#define CHROMECAST_MEDIA_CMA_DECODER_CAST_AUDIO_DECODER_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace chromecast { +namespace media { +struct AudioConfig; +class DecoderBufferBase; + +// Audio decoder interface. +class CastAudioDecoder { + public: + enum Status { + kDecodeOk, + kDecodeError, + }; + + enum OutputFormat { + kOutputSigned16, // Output signed 16-bit interleaved samples. + kOutputPlanarFloat, // Output planar float samples. + }; + + // The callback that is called when the decoder initialization is complete. + // |success| is true if initialization was successful; if |success| is false + // then the CastAudioDecoder instance is unusable and should be destroyed. + typedef base::Callback<void(bool success)> InitializedCallback; + typedef base::Callback<void( + Status status, + const scoped_refptr<media::DecoderBufferBase>& decoded)> DecodeCallback; + + // Creates a CastAudioDecoder instance for the given |config|. Decoding must + // occur on the same thread as |task_runner|. Returns an empty scoped_ptr if + // the decoder could not be created. + static scoped_ptr<CastAudioDecoder> Create( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const media::AudioConfig& config, + OutputFormat output_format, + const InitializedCallback& initialized_callback); + + // Given a CastAudioDecoder::OutputFormat, return the size of each sample in + // that OutputFormat in bytes. + static int OutputFormatSizeInBytes(CastAudioDecoder::OutputFormat format); + + CastAudioDecoder() {} + virtual ~CastAudioDecoder() {} + + // Converts encoded data to the |output_format|. Must be called on the same + // thread as |task_runner|. Decoded data will be passed to |decode_callback|. + // It is OK to call Decode before the |initialized_callback| has been called; + // those buffers will be queued until initialization completes, at which point + // they will be decoded in order (if initialization was successful), or + // ignored if initialization failed. + // It is OK to pass an end-of-stream DecoderBuffer as |data|. + // Returns |false| if the decoder is not ready yet. + virtual bool Decode(const scoped_refptr<media::DecoderBufferBase>& data, + const DecodeCallback& decode_callback) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(CastAudioDecoder); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_DECODER_CAST_AUDIO_DECODER_H_
diff --git a/chromecast/media/cma/decoder/cast_audio_decoder_android.cc b/chromecast/media/cma/decoder/cast_audio_decoder_android.cc new file mode 100644 index 0000000..669c688b --- /dev/null +++ b/chromecast/media/cma/decoder/cast_audio_decoder_android.cc
@@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/cma/decoder/cast_audio_decoder.h" + +#include "base/logging.h" + +namespace chromecast { +namespace media { + +// static +scoped_ptr<CastAudioDecoder> CastAudioDecoder::Create( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const media::AudioConfig& config, + OutputFormat output_format, + const InitializedCallback& initialized_callback) { + return scoped_ptr<CastAudioDecoder>(); +} + +// static +int CastAudioDecoder::OutputFormatSizeInBytes( + CastAudioDecoder::OutputFormat format) { + switch (format) { + case CastAudioDecoder::OutputFormat::kOutputSigned16: + return 2; + case CastAudioDecoder::OutputFormat::kOutputPlanarFloat: + return 4; + } + NOTREACHED(); + return 1; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/decoder/cast_audio_decoder_linux.cc b/chromecast/media/cma/decoder/cast_audio_decoder_linux.cc new file mode 100644 index 0000000..ea88ba42 --- /dev/null +++ b/chromecast/media/cma/decoder/cast_audio_decoder_linux.cc
@@ -0,0 +1,293 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/cma/decoder/cast_audio_decoder.h" + +#include <limits> +#include <queue> +#include <vector> + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "chromecast/media/cma/base/decoder_buffer_adapter.h" +#include "chromecast/media/cma/base/decoder_buffer_base.h" +#include "chromecast/media/cma/base/decoder_config_adapter.h" +#include "media/base/audio_buffer.h" +#include "media/base/audio_bus.h" +#include "media/base/cdm_context.h" +#include "media/base/channel_layout.h" +#include "media/base/channel_mixer.h" +#include "media/base/decoder_buffer.h" +#include "media/base/sample_format.h" +#include "media/filters/ffmpeg_audio_decoder.h" +#include "media/filters/opus_audio_decoder.h" + +namespace chromecast { +namespace media { + +namespace { + +const int kOpusSamplingRate = 48000; +const uint8 kFakeOpusExtraData[19] = { + 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd', // offset 0, OpusHead + 0, // offset 8, version + 2, // offset 9, channels + 0, 0, // offset 10, skip + static_cast<uint8>(kOpusSamplingRate & 0xFF), // offset 12, LE + static_cast<uint8>((kOpusSamplingRate >> 8) & 0xFF), + static_cast<uint8>((kOpusSamplingRate >> 16) & 0xFF), + static_cast<uint8>((kOpusSamplingRate >> 24) & 0xFF), + 0, 0, // offset 16, gain + 0, // offset 18, stereo mapping +}; + +const int kOutputChannelCount = 2; // Always output stereo audio. +const int kMaxChannelInput = 2; + +class CastAudioDecoderImpl : public CastAudioDecoder { + public: + CastAudioDecoderImpl( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const InitializedCallback& initialized_callback, + OutputFormat output_format) + : task_runner_(task_runner), + initialized_callback_(initialized_callback), + output_format_(output_format), + initialized_(false), + decode_pending_(false), + weak_factory_(this) {} + + ~CastAudioDecoderImpl() override {} + + void Initialize(const media::AudioConfig& config) { + DCHECK(!initialized_); + DCHECK_LE(config_.channel_number, kMaxChannelInput); + config_ = config; + if (config_.channel_number == 1) { + // If the input is mono, create a ChannelMixer to convert mono to stereo. + // TODO(kmackay) Support other channel format conversions? + mixer_.reset(new ::media::ChannelMixer(::media::CHANNEL_LAYOUT_MONO, + ::media::CHANNEL_LAYOUT_STEREO)); + } + base::WeakPtr<CastAudioDecoderImpl> self = weak_factory_.GetWeakPtr(); + if (config.codec == media::kCodecOpus) { + // Insert fake extradata to make OpusAudioDecoder work with v2mirroring. + if (config_.extra_data.empty() && + config_.samples_per_second == kOpusSamplingRate && + config_.channel_number == 2) + config_.extra_data.assign( + kFakeOpusExtraData, + kFakeOpusExtraData + sizeof(kFakeOpusExtraData)); + decoder_.reset(new ::media::OpusAudioDecoder(task_runner_)); + } else { + decoder_.reset(new ::media::FFmpegAudioDecoder( + task_runner_, make_scoped_refptr(new ::media::MediaLog()))); + } + decoder_->Initialize( + media::DecoderConfigAdapter::ToMediaAudioDecoderConfig(config_), + ::media::SetCdmReadyCB(), + base::Bind(&CastAudioDecoderImpl::OnInitialized, self), + base::Bind(&CastAudioDecoderImpl::OnDecoderOutput, self)); + // Unfortunately there is no result from decoder_->Initialize() until later + // (the pipeline status callback is posted to the task runner). + } + + // CastAudioDecoder implementation: + bool Decode(const scoped_refptr<media::DecoderBufferBase>& data, + const DecodeCallback& decode_callback) override { + DCHECK(!decode_callback.is_null()); + DCHECK(task_runner_->BelongsToCurrentThread()); + if (!initialized_ || decode_pending_) { + decode_queue_.push(std::make_pair(data, decode_callback)); + } else { + DecodeNow(data, decode_callback); + } + return true; + } + + private: + typedef std::pair<scoped_refptr<media::DecoderBufferBase>, DecodeCallback> + DecodeBufferCallbackPair; + + void DecodeNow(const scoped_refptr<media::DecoderBufferBase>& data, + const DecodeCallback& decode_callback) { + if (data->end_of_stream()) { + // Post the task to ensure that |decode_callback| is not called from + // within a call to Decode(). + task_runner_->PostTask(FROM_HERE, + base::Bind(decode_callback, kDecodeOk, data)); + return; + } + + // FFmpegAudioDecoder requires a timestamp to be set. + base::TimeDelta timestamp = + base::TimeDelta::FromMicroseconds(data->timestamp()); + if (timestamp == ::media::kNoTimestamp()) + data->set_timestamp(base::TimeDelta()); + + decode_pending_ = true; + decoder_->Decode(data->ToMediaBuffer(), + base::Bind(&CastAudioDecoderImpl::OnDecodeStatus, + weak_factory_.GetWeakPtr(), + timestamp, + decode_callback)); + } + + void OnInitialized(bool success) { + DCHECK(!initialized_); + LOG_IF(ERROR, !success) << "Failed to initialize FFmpegAudioDecoder"; + if (success) + initialized_ = true; + + if (success && !decode_queue_.empty()) { + const auto& d = decode_queue_.front(); + DecodeNow(d.first, d.second); + decode_queue_.pop(); + } + + if (!initialized_callback_.is_null()) + initialized_callback_.Run(initialized_); + } + + void OnDecodeStatus(base::TimeDelta buffer_timestamp, + const DecodeCallback& decode_callback, + ::media::AudioDecoder::Status status) { + Status result_status = kDecodeOk; + scoped_refptr<media::DecoderBufferBase> decoded; + if (status == ::media::AudioDecoder::kOk && !decoded_chunks_.empty()) { + decoded = ConvertDecoded(); + } else { + if (status != ::media::AudioDecoder::kOk) + result_status = kDecodeError; + decoded = new media::DecoderBufferAdapter(config_.id, + new ::media::DecoderBuffer(0)); + } + decoded_chunks_.clear(); + decoded->set_timestamp(buffer_timestamp); + decode_callback.Run(result_status, decoded); + + // Do not reset decode_pending_ to false until after the callback has + // finished running because the callback may call Decode(). + decode_pending_ = false; + + if (decode_queue_.empty()) + return; + + const auto& d = decode_queue_.front(); + // Calling DecodeNow() here does not result in a loop, because + // OnDecodeStatus() is always called asynchronously (guaranteed by the + // AudioDecoder interface). + DecodeNow(d.first, d.second); + decode_queue_.pop(); + } + + void OnDecoderOutput(const scoped_refptr<::media::AudioBuffer>& decoded) { + decoded_chunks_.push_back(decoded); + } + + scoped_refptr<media::DecoderBufferBase> ConvertDecoded() { + DCHECK(!decoded_chunks_.empty()); + int num_frames = 0; + for (auto& chunk : decoded_chunks_) + num_frames += chunk->frame_count(); + + // Copy decoded data into an AudioBus for conversion. + scoped_ptr<::media::AudioBus> decoded = + ::media::AudioBus::Create(config_.channel_number, num_frames); + int bus_frame_offset = 0; + for (auto& chunk : decoded_chunks_) { + chunk->ReadFrames( + chunk->frame_count(), 0, bus_frame_offset, decoded.get()); + bus_frame_offset += chunk->frame_count(); + } + + if (mixer_) { + // Convert to stereo if necessary. + scoped_ptr<::media::AudioBus> converted_to_stereo = + ::media::AudioBus::Create(kOutputChannelCount, num_frames); + mixer_->Transform(decoded.get(), converted_to_stereo.get()); + decoded.swap(converted_to_stereo); + } + + // Convert to the desired output format. + return FinishConversion(decoded.get()); + } + + scoped_refptr<media::DecoderBufferBase> FinishConversion( + ::media::AudioBus* bus) { + DCHECK_EQ(kOutputChannelCount, bus->channels()); + int size = bus->frames() * kOutputChannelCount * + OutputFormatSizeInBytes(output_format_); + scoped_refptr<::media::DecoderBuffer> result( + new ::media::DecoderBuffer(size)); + + if (output_format_ == kOutputSigned16) { + bus->ToInterleaved(bus->frames(), + OutputFormatSizeInBytes(output_format_), + result->writable_data()); + } else if (output_format_ == kOutputPlanarFloat) { + // Data in an AudioBus is already in planar float format; just copy each + // channel into the result buffer in order. + float* ptr = reinterpret_cast<float*>(result->writable_data()); + for (int c = 0; c < bus->channels(); ++c) { + memcpy(ptr, bus->channel(c), bus->frames() * sizeof(float)); + ptr += bus->frames(); + } + } else { + NOTREACHED(); + } + + result->set_duration(base::TimeDelta::FromMicroseconds( + bus->frames() * base::Time::kMicrosecondsPerSecond / + config_.samples_per_second)); + return make_scoped_refptr( + new media::DecoderBufferAdapter(config_.id, result)); + } + + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + InitializedCallback initialized_callback_; + OutputFormat output_format_; + media::AudioConfig config_; + scoped_ptr<::media::AudioDecoder> decoder_; + std::queue<DecodeBufferCallbackPair> decode_queue_; + bool initialized_; + scoped_ptr<::media::ChannelMixer> mixer_; + bool decode_pending_; + std::vector<scoped_refptr<::media::AudioBuffer>> decoded_chunks_; + base::WeakPtrFactory<CastAudioDecoderImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CastAudioDecoderImpl); +}; + +} // namespace + +// static +scoped_ptr<CastAudioDecoder> CastAudioDecoder::Create( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const media::AudioConfig& config, + OutputFormat output_format, + const InitializedCallback& initialized_callback) { + scoped_ptr<CastAudioDecoderImpl> decoder(new CastAudioDecoderImpl( + task_runner, initialized_callback, output_format)); + decoder->Initialize(config); + return decoder.Pass(); +} + +// static +int CastAudioDecoder::OutputFormatSizeInBytes( + CastAudioDecoder::OutputFormat format) { + switch (format) { + case CastAudioDecoder::OutputFormat::kOutputSigned16: + return 2; + case CastAudioDecoder::OutputFormat::kOutputPlanarFloat: + return 4; + } + NOTREACHED(); + return 1; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index 2f6fb610..726a861 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp
@@ -147,6 +147,20 @@ ], }, { + 'target_name': 'cma_decoder', + 'type': '<(component)', + 'dependencies': [ + 'cma_base', + '../../base/base.gyp:base', + '../../media/media.gyp:media', + ], + 'sources': [ + 'cma/decoder/cast_audio_decoder.h', + 'cma/decoder/cast_audio_decoder_android.cc', + 'cma/decoder/cast_audio_decoder_linux.cc', + ], + }, + { 'target_name': 'cma_ipc', 'type': '<(component)', 'dependencies': [
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index cf422a2..93722911 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp
@@ -53,8 +53,6 @@ 'dbus/amplifier_client.h', 'dbus/ap_manager_client.cc', 'dbus/ap_manager_client.h', - 'dbus/arc_bridge_client.cc', - 'dbus/arc_bridge_client.h', 'dbus/audio_dsp_client.cc', 'dbus/audio_dsp_client.h', 'dbus/audio_node.cc', @@ -82,8 +80,6 @@ 'dbus/fake_amplifier_client.h', 'dbus/fake_ap_manager_client.cc', 'dbus/fake_ap_manager_client.h', - 'dbus/fake_arc_bridge_client.cc', - 'dbus/fake_arc_bridge_client.h', 'dbus/fake_audio_dsp_client.cc', 'dbus/fake_audio_dsp_client.h', 'dbus/fake_cras_audio_client.cc',
diff --git a/chromeos/dbus/arc_bridge_client.cc b/chromeos/dbus/arc_bridge_client.cc deleted file mode 100644 index 584e10b..0000000 --- a/chromeos/dbus/arc_bridge_client.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#include "chromeos/dbus/arc_bridge_client.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" -#include "dbus/bus.h" -#include "dbus/message.h" -#include "dbus/object_path.h" -#include "dbus/object_proxy.h" - -namespace chromeos { - -namespace { - -// todo(denniskempin): Move constants to the chromiumos platform -// service_constants.h -const char kArcBridgeServicePath[] = "/org/chromium/arc"; -const char kArcBridgeServiceName[] = "org.chromium.arc"; -const char kArcBridgeServiceInterface[] = "org.chromium.arc"; - -const char kPingMethod[] = "Ping"; - -void OnVoidDBusMethod(const VoidDBusMethodCallback& callback, - dbus::Response* response) { - callback.Run(response ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE); -} - -class ArcBridgeClientImpl : public ArcBridgeClient { - public: - ArcBridgeClientImpl() : proxy_(nullptr), weak_ptr_factory_(this) {} - - ~ArcBridgeClientImpl() override {} - - // Calls Ping method. |callback| is called after the method call succeeds. - void Ping(const VoidDBusMethodCallback& callback) override { - DCHECK(proxy_); - - dbus::MethodCall method_call(kArcBridgeServiceInterface, kPingMethod); - proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, - base::Bind(&OnVoidDBusMethod, callback)); - } - - protected: - void Init(dbus::Bus* bus) override { - proxy_ = bus->GetObjectProxy(kArcBridgeServiceName, - dbus::ObjectPath(kArcBridgeServicePath)); - DCHECK(proxy_); - } - - private: - dbus::ObjectProxy* proxy_; - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<ArcBridgeClientImpl> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ArcBridgeClientImpl); -}; - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// -// ArcBridgeClient - -ArcBridgeClient::ArcBridgeClient() {} - -ArcBridgeClient::~ArcBridgeClient() {} - -// static -ArcBridgeClient* ArcBridgeClient::Create() { - return new ArcBridgeClientImpl(); -} - -} // namespace chromeos
diff --git a/chromeos/dbus/arc_bridge_client.h b/chromeos/dbus/arc_bridge_client.h deleted file mode 100644 index 11d568dd..0000000 --- a/chromeos/dbus/arc_bridge_client.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMEOS_ARC_BRIDGE_CLIENT_H_ -#define CHROMEOS_ARC_BRIDGE_CLIENT_H_ - -#include "base/basictypes.h" -#include "chromeos/chromeos_export.h" -#include "chromeos/dbus/dbus_client.h" -#include "chromeos/dbus/dbus_method_call_status.h" - -namespace dbus { -class ObjectPath; -} - -namespace chromeos { - -// Client for the Arc Bridge Service -class CHROMEOS_EXPORT ArcBridgeClient : public DBusClient { - public: - ~ArcBridgeClient() override; - - // Factory function, creates a new instance and returns ownership. - // For normal usage, access the singleton via DBusThreadManager::Get(). - static ArcBridgeClient* Create(); - - // Calls Ping method. |callback| is called after the method call succeeds. - virtual void Ping(const VoidDBusMethodCallback& callback) = 0; - - protected: - // Create() should be used instead. - ArcBridgeClient(); - - private: - DISALLOW_COPY_AND_ASSIGN(ArcBridgeClient); -}; - -} // namespace chromeos - -#endif // CHROMEOS_ARC_BRIDGE_CLIENT_H_
diff --git a/chromeos/dbus/dbus_client_bundle.cc b/chromeos/dbus/dbus_client_bundle.cc index 0397ff6..87e6598 100644 --- a/chromeos/dbus/dbus_client_bundle.cc +++ b/chromeos/dbus/dbus_client_bundle.cc
@@ -12,7 +12,6 @@ #include "chromeos/chromeos_switches.h" #include "chromeos/dbus/amplifier_client.h" #include "chromeos/dbus/ap_manager_client.h" -#include "chromeos/dbus/arc_bridge_client.h" #include "chromeos/dbus/audio_dsp_client.h" #include "chromeos/dbus/cras_audio_client.h" #include "chromeos/dbus/cros_disks_client.h" @@ -21,7 +20,6 @@ #include "chromeos/dbus/easy_unlock_client.h" #include "chromeos/dbus/fake_amplifier_client.h" #include "chromeos/dbus/fake_ap_manager_client.h" -#include "chromeos/dbus/fake_arc_bridge_client.h" #include "chromeos/dbus/fake_audio_dsp_client.h" #include "chromeos/dbus/fake_cras_audio_client.h" #include "chromeos/dbus/fake_cryptohome_client.h" @@ -85,7 +83,6 @@ } client_type_map[] = { { "amplifier", DBusClientBundle::AMPLIFIER }, { "ap", DBusClientBundle::AP_MANAGER }, - { "arc", DBusClientBundle::ARC_BRIDGE }, { "audio_dsp", DBusClientBundle::AUDIO_DSP }, { "bluetooth", DBusClientBundle::BLUETOOTH }, { "cras", DBusClientBundle::CRAS }, @@ -131,11 +128,6 @@ else amplifier_client_.reset(new FakeAmplifierClient); - if (!IsUsingStub(ARC_BRIDGE)) - arc_bridge_client_.reset(ArcBridgeClient::Create()); - else - arc_bridge_client_.reset(new FakeArcBridgeClient); - if (!IsUsingStub(AUDIO_DSP)) audio_dsp_client_.reset(AudioDspClient::Create()); else
diff --git a/chromeos/dbus/dbus_client_bundle.h b/chromeos/dbus/dbus_client_bundle.h index 2fd9e58..ea39ad9 100644 --- a/chromeos/dbus/dbus_client_bundle.h +++ b/chromeos/dbus/dbus_client_bundle.h
@@ -14,7 +14,6 @@ class AmplifierClient; class ApManagerClient; -class ArcBridgeClient; class AudioDspClient; class CrasAudioClient; class CrosDisksClient; @@ -81,7 +80,6 @@ PRIVET_DAEMON = 1 << 21, AMPLIFIER = 1 << 22, AUDIO_DSP = 1 << 23, - ARC_BRIDGE = 1 << 24, }; explicit DBusClientBundle(DBusClientTypeMask unstub_client_mask); @@ -104,8 +102,6 @@ ApManagerClient* ap_manager_client() { return ap_manager_client_.get(); } - ArcBridgeClient* arc_bridge_client() { return arc_bridge_client_.get(); } - AudioDspClient* audio_dsp_client() { return audio_dsp_client_.get(); } CrasAudioClient* cras_audio_client() { @@ -233,7 +229,6 @@ scoped_ptr<AmplifierClient> amplifier_client_; scoped_ptr<ApManagerClient> ap_manager_client_; - scoped_ptr<ArcBridgeClient> arc_bridge_client_; scoped_ptr<AudioDspClient> audio_dsp_client_; scoped_ptr<CrasAudioClient> cras_audio_client_; scoped_ptr<CrosDisksClient> cros_disks_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc index ab8db4f..fe590216 100644 --- a/chromeos/dbus/dbus_thread_manager.cc +++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -10,7 +10,6 @@ #include "chromeos/chromeos_switches.h" #include "chromeos/dbus/amplifier_client.h" #include "chromeos/dbus/ap_manager_client.h" -#include "chromeos/dbus/arc_bridge_client.h" #include "chromeos/dbus/audio_dsp_client.h" #include "chromeos/dbus/cras_audio_client.h" #include "chromeos/dbus/cros_disks_client.h" @@ -108,10 +107,6 @@ return client_bundle_->amplifier_client(); } -ArcBridgeClient* DBusThreadManager::GetArcBridgeClient() { - return client_bundle_->arc_bridge_client(); -} - ApManagerClient* DBusThreadManager::GetApManagerClient() { return client_bundle_->ap_manager_client(); } @@ -246,7 +241,6 @@ void DBusThreadManager::InitializeClients() { GetAmplifierClient()->Init(GetSystemBus()); GetApManagerClient()->Init(GetSystemBus()); - GetArcBridgeClient()->Init(GetSystemBus()); GetAudioDspClient()->Init(GetSystemBus()); GetCrasAudioClient()->Init(GetSystemBus()); GetCrosDisksClient()->Init(GetSystemBus()); @@ -397,11 +391,6 @@ DBusThreadManager::Get()->client_bundle_->amplifier_client_ = client.Pass(); } -void DBusThreadManagerSetter::SetArcBridgeClient( - scoped_ptr<ArcBridgeClient> client) { - DBusThreadManager::Get()->client_bundle_->arc_bridge_client_ = client.Pass(); -} - void DBusThreadManagerSetter::SetAudioDspClient( scoped_ptr<AudioDspClient> client) { DBusThreadManager::Get()->client_bundle_->audio_dsp_client_ = client.Pass();
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h index eaf9109f..83f3c26 100644 --- a/chromeos/dbus/dbus_thread_manager.h +++ b/chromeos/dbus/dbus_thread_manager.h
@@ -27,7 +27,6 @@ // Style Note: Clients are sorted by names. class AmplifierClient; class ApManagerClient; -class ArcBridgeClient; class AudioDspClient; class CrasAudioClient; class CrosDisksClient; @@ -112,7 +111,6 @@ // pointers after DBusThreadManager has been shut down. AmplifierClient* GetAmplifierClient(); ApManagerClient* GetApManagerClient(); - ArcBridgeClient* GetArcBridgeClient(); AudioDspClient* GetAudioDspClient(); CrasAudioClient* GetCrasAudioClient(); CrosDisksClient* GetCrosDisksClient(); @@ -187,7 +185,6 @@ ~DBusThreadManagerSetter(); void SetAmplifierClient(scoped_ptr<AmplifierClient> client); - void SetArcBridgeClient(scoped_ptr<ArcBridgeClient> client); void SetAudioDspClient(scoped_ptr<AudioDspClient> client); void SetCrasAudioClient(scoped_ptr<CrasAudioClient> client); void SetCrosDisksClient(scoped_ptr<CrosDisksClient> client);
diff --git a/chromeos/dbus/fake_arc_bridge_client.cc b/chromeos/dbus/fake_arc_bridge_client.cc deleted file mode 100644 index d14df0e..0000000 --- a/chromeos/dbus/fake_arc_bridge_client.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromeos/dbus/fake_arc_bridge_client.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" - -namespace chromeos { - -namespace { - -void OnVoidDBusMethod(const VoidDBusMethodCallback& callback) { - callback.Run(DBUS_METHOD_CALL_SUCCESS); -} - -} // anonymous namespace - -FakeArcBridgeClient::FakeArcBridgeClient() { -} - -FakeArcBridgeClient::~FakeArcBridgeClient() { -} - -void FakeArcBridgeClient::Init(dbus::Bus* bus) { -} - -void FakeArcBridgeClient::Ping(const VoidDBusMethodCallback& callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&OnVoidDBusMethod, callback)); -} - -} // namespace chromeos
diff --git a/chromeos/dbus/fake_arc_bridge_client.h b/chromeos/dbus/fake_arc_bridge_client.h deleted file mode 100644 index eb41b508..0000000 --- a/chromeos/dbus/fake_arc_bridge_client.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMEOS_FAKE_ARC_BRIDGE_CLIENT_CLIENT_H_ -#define CHROMEOS_FAKE_ARC_BRIDGE_CLIENT_CLIENT_H_ - -#include "base/basictypes.h" -#include "chromeos/chromeos_export.h" -#include "chromeos/dbus/arc_bridge_client.h" -#include "chromeos/dbus/dbus_client.h" - -namespace chromeos { - -// A fake implementation of ArcBridgeClient. -class CHROMEOS_EXPORT FakeArcBridgeClient : public ArcBridgeClient { - public: - FakeArcBridgeClient(); - ~FakeArcBridgeClient() override; - - // DBusClient overrides: - void Init(dbus::Bus* bus) override; - - // ArcBridgeClient overrides: - void Ping(const VoidDBusMethodCallback& callback) override; - - private: - DISALLOW_COPY_AND_ASSIGN(FakeArcBridgeClient); -}; - -} // namespace chromeos - -#endif // CHROMEOS_FAKE_ARC_BRIDGE_CLIENT_CLIENT_H_
diff --git a/components/arc.gypi b/components/arc.gypi index 3773f09..7cf871c 100644 --- a/components/arc.gypi +++ b/components/arc.gypi
@@ -25,6 +25,8 @@ 'arc/common/arc_instance_messages.h', 'arc/common/arc_message_generator.cc', 'arc/common/arc_message_generator.h', + 'arc/common/arc_message_traits.h', + 'arc/common/arc_message_types.h', ], }, ],
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index e6f40684..7fbfd24 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -13,6 +13,7 @@ deps = [ "//base", + "//base:prefs", "//chromeos", "//ipc", ]
diff --git a/components/arc/arc_bridge_service.cc b/components/arc/arc_bridge_service.cc index af2835d..640e379 100644 --- a/components/arc/arc_bridge_service.cc +++ b/components/arc/arc_bridge_service.cc
@@ -57,6 +57,16 @@ observer_list_.RemoveObserver(observer); } +void ArcBridgeService::AddAppObserver(AppObserver* observer) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + app_observer_list_.AddObserver(observer); +} + +void ArcBridgeService::RemoveAppObserver(AppObserver* observer) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + app_observer_list_.RemoveObserver(observer); +} + void ArcBridgeService::SetState(State state) { DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); // DCHECK on enum classes not supported.
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h index 78e8fa8..a3c1fe6 100644 --- a/components/arc/arc_bridge_service.h +++ b/components/arc/arc_bridge_service.h
@@ -64,6 +64,7 @@ STOPPING, }; + // Notifies life cycle events of ArcBridgeService. class Observer { public: // Called whenever the state of the bridge has changed. @@ -79,6 +80,22 @@ virtual ~Observer() {} }; + // Notifies ARC apps related events. + class AppObserver { + public: + // Called whenever ARC sends information about available apps. + virtual void OnAppListRefreshed(const std::vector<AppInfo>& apps) {} + + // Called whenever ARC sends app icon data for specific scale factor. + virtual void OnAppIcon(const std::string& package, + const std::string& activity, + ScaleFactor scale_factor, + const std::vector<uint8_t>& icon_png_data) {} + + protected: + virtual ~AppObserver() {} + }; + virtual ~ArcBridgeService(); // Creates instance of |ArcBridgeService| for normal use. @@ -113,6 +130,11 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + // Adds or removes ARC app observers. This can only be called on the thread + // that this class was created on. + void AddAppObserver(AppObserver* observer); + void RemoveAppObserver(AppObserver* observer); + // Gets the current state of the bridge service. State state() const { return state_; } @@ -129,6 +151,18 @@ const std::string& device_type, base::ScopedFD fd) = 0; + // Requests to refresh an app list. + virtual bool RefreshAppList() = 0; + + // Requests to launch an app. + virtual bool LaunchApp(const std::string& package, + const std::string& activity) = 0; + + // Requests to load an icon of specific scale_factor. + virtual bool RequestAppIcon(const std::string& package, + const std::string& activity, + ScaleFactor scale_factor) = 0; + protected: ArcBridgeService(); @@ -144,11 +178,17 @@ base::ObserverList<Observer>& observer_list() { return observer_list_; } + base::ObserverList<AppObserver>& app_observer_list() { + return app_observer_list_; + } + private: scoped_refptr<base::SequencedTaskRunner> origin_task_runner_; base::ObserverList<Observer> observer_list_; + base::ObserverList<AppObserver> app_observer_list_; + // If the ARC instance service is available. bool available_;
diff --git a/components/arc/arc_bridge_service_impl.cc b/components/arc/arc_bridge_service_impl.cc index 1a1c954..b5611b7 100644 --- a/components/arc/arc_bridge_service_impl.cc +++ b/components/arc/arc_bridge_service_impl.cc
@@ -108,6 +108,38 @@ name, device_type, base::FileDescriptor(fd.Pass()))); } +bool ArcBridgeServiceImpl::RefreshAppList() { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + if (state() != State::READY) { + LOG(ERROR) << "Called RefreshAppList when the service is not ready"; + return false; + } + return ipc_channel_->Send(new ArcInstanceMsg_RefreshApps()); +} + +bool ArcBridgeServiceImpl::LaunchApp(const std::string& package, + const std::string& activity) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + if (state() != State::READY) { + LOG(ERROR) << "Called LaunchApp when the service is not ready"; + return false; + } + return ipc_channel_->Send(new ArcInstanceMsg_LaunchApp(package, activity)); +} + +bool ArcBridgeServiceImpl::RequestAppIcon(const std::string& package, + const std::string& activity, + ScaleFactor scale_factor) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + if (state() != State::READY) { + LOG(ERROR) << "Called RequestAppIcon when the service is not ready"; + return false; + } + return ipc_channel_->Send(new ArcInstanceMsg_RequestAppIcon(package, + activity, + scale_factor)); +} + void ArcBridgeServiceImpl::SocketConnect(const base::FilePath& socket_path) { DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); if (state() != State::STOPPED) { @@ -226,6 +258,8 @@ IPC_BEGIN_MESSAGE_MAP(ArcBridgeServiceImpl, message) IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceBootPhase, OnInstanceBootPhase) + IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_AppListRefreshed, OnAppListRefreshed) + IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_AppIcon, OnAppIcon) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -234,6 +268,23 @@ return handled; } +void ArcBridgeServiceImpl::OnAppListRefreshed( + const std::vector<arc::AppInfo>& apps) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(AppObserver, app_observer_list(), OnAppListRefreshed(apps)); +} + +void ArcBridgeServiceImpl::OnAppIcon( + const std::string& package, + const std::string& activity, + ScaleFactor scale_factor, + const std::vector<uint8_t>& icon_png_data) { + DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(AppObserver, + app_observer_list(), + OnAppIcon(package, activity, scale_factor, icon_png_data)); +} + void ArcBridgeServiceImpl::OnArcAvailable(bool arc_available) { DCHECK(origin_task_runner()->RunsTasksOnCurrentThread()); if (available() == arc_available)
diff --git a/components/arc/arc_bridge_service_impl.h b/components/arc/arc_bridge_service_impl.h index d65e712..7482363 100644 --- a/components/arc/arc_bridge_service_impl.h +++ b/components/arc/arc_bridge_service_impl.h
@@ -38,6 +38,18 @@ const std::string& device_type, base::ScopedFD fd) override; + // Requests to refresh an app list. + bool RefreshAppList() override; + + // Requests to launch an app. + bool LaunchApp(const std::string& package, + const std::string& activity) override; + + // Requests to load an icon of specific scale_factor. + bool RequestAppIcon(const std::string& package, + const std::string& activity, + ScaleFactor scale_factor) override; + private: friend class ArcBridgeTest; FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic); @@ -70,6 +82,15 @@ // Called when the instance has reached a boot phase void OnInstanceBootPhase(InstanceBootPhase phase); + // Called whenever ARC sends information about available apps. + void OnAppListRefreshed(const std::vector<arc::AppInfo>& apps); + + // Called whenever ARC sends app icon data for specific scale factor. + void OnAppIcon(const std::string& package, + const std::string& activity, + ScaleFactor scale_factor, + const std::vector<uint8_t>& icon_png_data); + // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/components/arc/common/arc_host_messages.h b/components/arc/common/arc_host_messages.h index 116de0c..d7ecfdf 100644 --- a/components/arc/common/arc_host_messages.h +++ b/components/arc/common/arc_host_messages.h
@@ -5,6 +5,9 @@ // Messages sent from the ARC instance to the host. // Multiply-included message file, hence no include guard. +#include <string> +#include <vector> + #include "ipc/ipc_message_macros.h" #include "components/arc/common/arc_message_types.h" @@ -15,3 +18,21 @@ IPC_MESSAGE_CONTROL1(ArcInstanceHostMsg_InstanceBootPhase, arc::InstanceBootPhase) + +// Sends a list of available ARC apps to Chrome. Members of AppInfo must contain +// non-empty string. This message is sent in response to +// ArcInstanceMsg_RefreshApps message from Chrome to ARC and when ARC receives +// boot completed notification. +IPC_MESSAGE_CONTROL1(ArcInstanceHostMsg_AppListRefreshed, + std::vector<arc::AppInfo> /* apps */) + +// Sends an icon of required |scale_factor| for specific ARC app. The app is +// defined by |package| and |activity|. The icon content cannot be empty and +// must match to |scale_factor| assuming 48x48 for SCALE_FACTOR_100P. +// |scale_factor| is an enum defined at ui/base/layout.h. This message is sent +// in response to ArcInstanceMsg_RequestIcon from Chrome to ARC. +IPC_MESSAGE_CONTROL4(ArcInstanceHostMsg_AppIcon, + std::string, /* package */ + std::string, /* activity */ + arc::ScaleFactor, /* scale_factor */ + std::vector<uint8_t> /* icon_png_data */)
diff --git a/components/arc/common/arc_instance_messages.h b/components/arc/common/arc_instance_messages.h index 94870469..31597d2 100644 --- a/components/arc/common/arc_instance_messages.h +++ b/components/arc/common/arc_instance_messages.h
@@ -7,6 +7,8 @@ #include <stdint.h> +#include <string> + #include "base/file_descriptor_posix.h" #include "ipc/ipc_message_macros.h" @@ -24,3 +26,23 @@ std::string, /* name */ std::string, /* device_type */ base::FileDescriptor /* fd */) + +// Sends a request to ARC to refresh a list of ARC apps. +// ArcInstanceMsg_RefreshApps is expected in response to this message. However, +// response may not be sent if ARC is not ready yet (boot completed event is +// not received). +IPC_MESSAGE_CONTROL0(ArcInstanceMsg_RefreshApps) + +// Sends a request to ARC to launch an ARC app defined by |package| and +// |activity|, which cannot be empty. +IPC_MESSAGE_CONTROL2(ArcInstanceMsg_LaunchApp, + std::string, /* package */ + std::string /* activity */) + +// Sends a request to ARC for the ARC app icon of a required scale factor. +// Scale factor is an enum defined at ui/base/layout.h. App is defined by +// package and activity, which cannot be empty. +IPC_MESSAGE_CONTROL3(ArcInstanceMsg_RequestAppIcon, + std::string, /* package */ + std::string, /* activity */ + arc::ScaleFactor /* scale factor */)
diff --git a/components/arc/common/arc_message_generator.h b/components/arc/common/arc_message_generator.h index 2b302a6..bd50a43 100644 --- a/components/arc/common/arc_message_generator.h +++ b/components/arc/common/arc_message_generator.h
@@ -7,3 +7,4 @@ // Not using the full path since this is also expected to be compiled in ARC. #include "arc_host_messages.h" #include "arc_instance_messages.h" +#include "arc_message_traits.h"
diff --git a/components/arc/common/arc_message_traits.h b/components/arc/common/arc_message_traits.h new file mode 100644 index 0000000..9d0938f --- /dev/null +++ b/components/arc/common/arc_message_traits.h
@@ -0,0 +1,17 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/arc/common/arc_message_types.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" + +IPC_ENUM_TRAITS_MIN_MAX_VALUE(arc::ScaleFactor, + arc::ScaleFactor::SCALE_FACTOR_100P, + arc::ScaleFactor::NUM_SCALE_FACTORS); + +IPC_STRUCT_TRAITS_BEGIN(arc::AppInfo) + IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(package) + IPC_STRUCT_TRAITS_MEMBER(activity) +IPC_STRUCT_TRAITS_END()
diff --git a/components/arc/common/arc_message_types.h b/components/arc/common/arc_message_types.h index e07193d..5971a6b 100644 --- a/components/arc/common/arc_message_types.h +++ b/components/arc/common/arc_message_types.h
@@ -5,7 +5,10 @@ #ifndef COMPONENTS_ARC_COMMON_MESSAGE_TYPES #define COMPONENTS_ARC_COMMON_MESSAGE_TYPES +#include <string> + namespace arc { + // Describing the boot phase of the ARC instance, as defined by AOSP in // com.android.server.SystemService enum class InstanceBootPhase { @@ -35,6 +38,30 @@ // Last enum entry for IPC_ENUM_TRAITS LAST = BOOT_COMPLETED }; -} + +// Duplicates ui::ScaleFactor enum in order to be accessible on Android side. +enum ScaleFactor : int { + SCALE_FACTOR_NONE = 0, + SCALE_FACTOR_100P, + SCALE_FACTOR_125P, + SCALE_FACTOR_133P, + SCALE_FACTOR_140P, + SCALE_FACTOR_150P, + SCALE_FACTOR_180P, + SCALE_FACTOR_200P, + SCALE_FACTOR_250P, + SCALE_FACTOR_300P, + + NUM_SCALE_FACTORS +}; + +// Describes ARC app. +struct AppInfo { + std::string name; + std::string package; + std::string activity; +}; + +} // namespace arc #endif // COMPONENTS_ARC_COMMON_MESSAGE_TYPES
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index d2bea33..a1ceea41 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -714,10 +714,6 @@ WebFormControlElementToFormField(element, form_util::EXTRACT_VALUE, &field); } - gfx::RectF bounding_box_scaled = form_util::GetScaledBoundingBox( - render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), - &element_); - std::vector<base::string16> data_list_values; std::vector<base::string16> data_list_labels; const WebInputElement* input_element = toWebInputElement(&element); @@ -736,7 +732,8 @@ data_list_labels)); Send(new AutofillHostMsg_QueryFormFieldAutofill( - routing_id(), autofill_query_id_, form, field, bounding_box_scaled)); + routing_id(), autofill_query_id_, form, field, + gfx::RectF(element_.boundsInViewport()))); } void AutofillAgent::FillFieldWithValue(const base::string16& value,
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index e1869e8..5c7f0d6 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1636,14 +1636,6 @@ return true; } -gfx::RectF GetScaledBoundingBox(float scale, WebElement* element) { - gfx::Rect bounding_box(element->boundsInViewportSpace()); - return gfx::RectF(bounding_box.x() * scale, - bounding_box.y() * scale, - bounding_box.width() * scale, - bounding_box.height() * scale); -} - void PreviewSuggestion(const base::string16& suggestion, const base::string16& user_input, blink::WebFormControlElement* input_element) {
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h index dd1b1271b..4b470404 100644 --- a/components/autofill/content/renderer/form_autofill_util.h +++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -229,9 +229,6 @@ // are of the type <script>, <meta>, or <title>. bool IsWebElementEmpty(const blink::WebElement& element); -// Return a gfx::RectF that is the bounding box for |element| scaled by |scale|. -gfx::RectF GetScaledBoundingBox(float scale, blink::WebElement* element); - // Previews |suggestion| in |input_element| and highlights the suffix of // |suggestion| not included in the |input_element| text. |input_element| must // not be null. |user_input| should be the text typed by the user into
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index 4247b5f1..a80fef1 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1420,7 +1420,6 @@ DCHECK(iter != web_input_to_password_info_.end()); selected_element = iter->second.password_field; } - gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); blink::WebInputElement username; if (!show_on_password_field || !user_input.isPasswordField()) { @@ -1430,12 +1429,6 @@ web_element_to_password_info_key_.find(user_input); DCHECK(key_it != web_element_to_password_info_key_.end()); - float scale = - render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(); - gfx::RectF bounding_box_scaled(bounding_box.x() * scale, - bounding_box.y() * scale, - bounding_box.width() * scale, - bounding_box.height() * scale); int options = 0; if (show_all) options |= SHOW_ALL; @@ -1444,9 +1437,10 @@ base::string16 username_string( username.isNull() ? base::string16() : static_cast<base::string16>(user_input.value())); + Send(new AutofillHostMsg_ShowPasswordSuggestions( routing_id(), key_it->second, field.text_direction, username_string, - options, bounding_box_scaled)); + options, gfx::RectF(selected_element.boundsInViewport()))); username_query_prefix_ = username_string; return CanShowSuggestion(fill_data, username_string, show_all); }
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc index 17dfbea..4d1c8cc 100644 --- a/components/autofill/content/renderer/password_generation_agent.cc +++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -411,27 +411,16 @@ } void PasswordGenerationAgent::ShowGenerationPopup() { - gfx::RectF bounding_box_scaled = form_util::GetScaledBoundingBox( - render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), - &generation_element_); - Send(new AutofillHostMsg_ShowPasswordGenerationPopup( - routing_id(), - bounding_box_scaled, - generation_element_.maxLength(), - *generation_form_data_->form)); + routing_id(), gfx::RectF(generation_element_.boundsInViewport()), + generation_element_.maxLength(), *generation_form_data_->form)); generation_popup_shown_ = true; } void PasswordGenerationAgent::ShowEditingPopup() { - gfx::RectF bounding_box_scaled = form_util::GetScaledBoundingBox( - render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), - &generation_element_); - Send(new AutofillHostMsg_ShowPasswordEditingPopup( - routing_id(), - bounding_box_scaled, + routing_id(), gfx::RectF(generation_element_.boundsInViewport()), *generation_form_data_->form)); editing_popup_shown_ = true;
diff --git a/components/autofill/core/browser/test_autofill_driver.cc b/components/autofill/core/browser/test_autofill_driver.cc index 3eaacd5..38a83ed 100644 --- a/components/autofill/core/browser/test_autofill_driver.cc +++ b/components/autofill/core/browser/test_autofill_driver.cc
@@ -14,9 +14,7 @@ new base::SequencedWorkerPoolOwner(4, "TestAutofillDriver")), url_request_context_(NULL) {} -TestAutofillDriver::~TestAutofillDriver() { - blocking_pool_owner_->pool()->Shutdown(); -} +TestAutofillDriver::~TestAutofillDriver() {} bool TestAutofillDriver::IsOffTheRecord() const { return false;
diff --git a/components/autofill/core/common/form_field_data.cc b/components/autofill/core/common/form_field_data.cc index 54db610..7b8d105 100644 --- a/components/autofill/core/common/form_field_data.cc +++ b/components/autofill/core/common/form_field_data.cc
@@ -4,8 +4,6 @@ #include "components/autofill/core/common/form_field_data.h" -#include <tuple> - #include "base/pickle.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -118,16 +116,35 @@ } bool FormFieldData::operator<(const FormFieldData& field) const { + // This does not use std::tie() as that generates more implicit variables + // than the max-vartrack-size for var-tracking-assignments when compiling + // for Android, producing build warnings. (See https://crbug.com/555171 for + // context.) + // Like operator==, this ignores the value. + if (label < field.label) return true; + if (label > field.label) return false; + if (name < field.name) return true; + if (name > field.name) return false; + if (form_control_type < field.form_control_type) return true; + if (form_control_type > field.form_control_type) return false; + if (autocomplete_attribute < field.autocomplete_attribute) return true; + if (autocomplete_attribute > field.autocomplete_attribute) return false; + if (max_length < field.max_length) return true; + if (max_length > field.max_length) return false; // Skip |is_checked| and |is_autofilled| as in SameFieldAs. + if (is_checkable < field.is_checkable) return true; + if (is_checkable > field.is_checkable) return false; + if (is_focusable < field.is_focusable) return true; + if (is_focusable > field.is_focusable) return false; + if (should_autocomplete < field.should_autocomplete) return true; + if (should_autocomplete > field.should_autocomplete) return false; + if (role < field.role) return true; + if (role > field.role) return false; + if (text_direction < field.text_direction) return true; + if (text_direction > field.text_direction) return false; // See operator== above for why we don't check option_values/contents. - return std::tie(label, name, form_control_type, autocomplete_attribute, - max_length, is_checkable, is_focusable, should_autocomplete, - role, text_direction) < - std::tie(field.label, field.name, field.form_control_type, - field.autocomplete_attribute, field.max_length, - field.is_checkable, field.is_focusable, - field.should_autocomplete, field.role, field.text_direction); + return false; } void SerializeFormFieldData(const FormFieldData& field_data,
diff --git a/components/browser_sync/browser/profile_sync_service.cc b/components/browser_sync/browser/profile_sync_service.cc index 3b8bf73..ba28615 100644 --- a/components/browser_sync/browser/profile_sync_service.cc +++ b/components/browser_sync/browser/profile_sync_service.cc
@@ -898,6 +898,7 @@ encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes(); passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; catch_up_configure_in_progress_ = false; + access_token_.clear(); request_access_token_retry_timer_.Stop(); // Revert to "no auth error". if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
diff --git a/components/component_updater/component_updater_service_unittest.cc b/components/component_updater/component_updater_service_unittest.cc index 9d78eb8..a5a839d 100644 --- a/components/component_updater/component_updater_service_unittest.cc +++ b/components/component_updater/component_updater_service_unittest.cc
@@ -174,7 +174,6 @@ ComponentUpdaterTest::~ComponentUpdaterTest() { EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1); - worker_pool_->pool()->Shutdown(); component_updater_.reset(); }
diff --git a/components/crash.gypi b/components/crash.gypi index d12d5b4..f2e790c 100644 --- a/components/crash.gypi +++ b/components/crash.gypi
@@ -345,6 +345,7 @@ }, }, { + # GN version: //components/crash/content/tools:crash_service 'target_name': 'breakpad_crash_service_win64', 'type': 'static_library', 'dependencies': [
diff --git a/components/crash/content/tools/BUILD.gn b/components/crash/content/tools/BUILD.gn index 82f282b..b781bd5 100644 --- a/components/crash/content/tools/BUILD.gn +++ b/components/crash/content/tools/BUILD.gn
@@ -2,17 +2,17 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -if (is_win) { - source_set("crash_service") { - sources = [ - "crash_service.cc", - "crash_service.h", - ] +assert(is_win) - deps = [ - "//base", - "//breakpad:breakpad_handler", - "//breakpad:breakpad_sender", - ] - } +source_set("crash_service") { + sources = [ + "crash_service.cc", + "crash_service.h", + ] + + deps = [ + "//base", + "//breakpad:breakpad_handler", + "//breakpad:breakpad_sender", + ] }
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn index ab91035..9c2a97c 100644 --- a/components/exo/BUILD.gn +++ b/components/exo/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") import("//testing/test.gni") source_set("exo") { @@ -87,6 +88,10 @@ "//ui/message_center", "//ui/views", ] + + if (use_ozone) { + deps += [ "//ui/ozone" ] + } } test("exo_unittests") {
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index dfcc0923b..40bbd7f01 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -13,9 +13,12 @@ #include "base/trace_event/trace_event_argument.h" #include "components/exo/surface.h" #include "ui/aura/window.h" +#include "ui/aura/window_property.h" #include "ui/base/hit_test.h" #include "ui/views/widget/widget.h" +DECLARE_WINDOW_PROPERTY_TYPE(std::string*) + namespace exo { namespace { @@ -64,11 +67,13 @@ //////////////////////////////////////////////////////////////////////////////// // ShellSurface, public: +DEFINE_LOCAL_WINDOW_PROPERTY_KEY(std::string*, kApplicationIdKey, nullptr) + ShellSurface::ShellSurface(Surface* surface) : surface_(surface) { surface_->SetSurfaceDelegate(this); surface_->AddSurfaceObserver(this); - surface_->SetVisible(true); - surface_->SetEnabled(true); + surface_->Show(); + set_owned_by_client(); } ShellSurface::~ShellSurface() { @@ -93,6 +98,9 @@ widget_.reset(new views::Widget); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); + widget_->GetNativeWindow()->SetName("ExoShellSurface"); + widget_->GetNativeWindow()->AddChild(surface_); + SetApplicationId(widget_->GetNativeWindow(), &application_id_); // The position of a standard top level shell surface is managed by Ash. ash::wm::GetWindowState(widget_->GetNativeWindow()) @@ -112,6 +120,9 @@ widget_.reset(new views::Widget); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); + widget_->GetNativeWindow()->SetName("ExoShellSurface"); + widget_->GetNativeWindow()->AddChild(surface_); + SetApplicationId(widget_->GetNativeWindow(), &application_id_); } void ShellSurface::SetFullscreen() { @@ -127,6 +138,9 @@ widget_.reset(new views::Widget); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); + widget_->GetNativeWindow()->SetName("ExoShellSurface"); + widget_->GetNativeWindow()->AddChild(surface_); + SetApplicationId(widget_->GetNativeWindow(), &application_id_); } void ShellSurface::SetTitle(const base::string16& title) { @@ -138,11 +152,40 @@ widget_->UpdateWindowTitle(); } +// static +void ShellSurface::SetApplicationId(aura::Window* window, + std::string* application_id) { + window->SetProperty(kApplicationIdKey, application_id); +} + +// static +const std::string ShellSurface::GetApplicationId(aura::Window* window) { + std::string* string_ptr = window->GetProperty(kApplicationIdKey); + return string_ptr ? *string_ptr : std::string(); +} + +void ShellSurface::SetApplicationId(const std::string& application_id) { + TRACE_EVENT1("exo", "ShellSurface::SetApplicationId", "application_id", + application_id); + + application_id_ = application_id; +} + +void ShellSurface::Move() { + TRACE_EVENT0("exo", "ShellSurface::Move"); + + if (widget_) { + widget_->RunMoveLoop(gfx::Vector2d(), views::Widget::MOVE_LOOP_SOURCE_MOUSE, + views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE); + } +} + scoped_refptr<base::trace_event::TracedValue> ShellSurface::AsTracedValue() const { scoped_refptr<base::trace_event::TracedValue> value = new base::trace_event::TracedValue; value->SetString("title", base::UTF16ToUTF8(title_)); + value->SetString("application_id", application_id_); return value; } @@ -152,10 +195,14 @@ void ShellSurface::OnSurfaceCommit() { surface_->CommitSurfaceHierarchy(); if (widget_) { + // Update surface bounds and widget size. + gfx::Point origin; + views::View::ConvertPointToWidget(this, &origin); + surface_->SetBounds(gfx::Rect(origin, surface_->layer()->size())); widget_->SetSize(widget_->non_client_view()->GetPreferredSize()); // Show widget if not already visible. - if (!widget_->GetNativeWindow()->TargetVisibility()) + if (!widget_->IsClosed() && !widget_->IsVisible()) widget_->Show(); } } @@ -189,7 +236,7 @@ } views::View* ShellSurface::GetContentsView() { - return surface_; + return this; } views::NonClientFrameView* ShellSurface::CreateNonClientFrameView( @@ -197,4 +244,11 @@ return new CustomFrameView(widget); } +//////////////////////////////////////////////////////////////////////////////// +// views::Views overrides: + +gfx::Size ShellSurface::GetPreferredSize() const { + return surface_ ? surface_->GetPreferredSize() : gfx::Size(); +} + } // namespace exo
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index 4107383..1c2bad32 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -28,7 +28,8 @@ // metadata like title and class, etc. class ShellSurface : public SurfaceDelegate, public SurfaceObserver, - public views::WidgetDelegate { + public views::WidgetDelegate, + public views::View { public: explicit ShellSurface(Surface* surface); ~ShellSurface() override; @@ -45,6 +46,18 @@ // Set title for surface. void SetTitle(const base::string16& title); + // Sets the application ID for the window. The application ID identifies the + // general class of applications to which the window belongs. + static void SetApplicationId(aura::Window* window, + std::string* application_id); + static const std::string GetApplicationId(aura::Window* window); + + // Set application id for surface. + void SetApplicationId(const std::string& application_id); + + // Start an interactive move of surface. + void Move(); + // Returns a trace value representing the state of the surface. scoped_refptr<base::trace_event::TracedValue> AsTracedValue() const; @@ -63,10 +76,14 @@ views::NonClientFrameView* CreateNonClientFrameView( views::Widget* widget) override; + // Overridden from views::View: + gfx::Size GetPreferredSize() const override; + private: scoped_ptr<views::Widget> widget_; Surface* surface_; base::string16 title_; + std::string application_id_; DISALLOW_COPY_AND_ASSIGN(ShellSurface); };
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index 3a08c04d..0f25a73 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "components/exo/buffer.h" #include "components/exo/shell_surface.h" @@ -82,5 +83,39 @@ surface->Commit(); } +TEST_F(ShellSurfaceTest, SetApplicationId) { + scoped_ptr<Surface> surface(new Surface); + scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); + + shell_surface->SetToplevel(); + surface->Commit(); + EXPECT_EQ("", ShellSurface::GetApplicationId( + shell_surface->GetWidget()->GetNativeWindow())); + shell_surface->SetApplicationId("test"); + EXPECT_EQ("test", ShellSurface::GetApplicationId( + shell_surface->GetWidget()->GetNativeWindow())); +} + +void DestroyShellSurface(scoped_ptr<ShellSurface>* shell_surface) { + shell_surface->reset(); +} + +TEST_F(ShellSurfaceTest, Move) { + scoped_ptr<Surface> surface(new Surface); + scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); + + // Map shell surface. + shell_surface->SetToplevel(); + surface->Commit(); + + // Post a task that will destroy the shell surface and then start an + // interactive move. The interactive move should end when surface is + // destroyed. + base::MessageLoopForUI::current()->PostTask( + FROM_HERE, + base::Bind(&DestroyShellSurface, base::Unretained(&shell_surface))); + shell_surface->Move(); +} + } // namespace } // namespace exo
diff --git a/components/exo/sub_surface_unittest.cc b/components/exo/sub_surface_unittest.cc index 8c3c2ff..2d4ab5c 100644 --- a/components/exo/sub_surface_unittest.cc +++ b/components/exo/sub_surface_unittest.cc
@@ -44,9 +44,9 @@ scoped_ptr<SubSurface> sub_surface2( new SubSurface(surface2.get(), parent.get())); - ASSERT_EQ(2, parent->child_count()); - EXPECT_EQ(surface1.get(), parent->child_at(0)); - EXPECT_EQ(surface2.get(), parent->child_at(1)); + ASSERT_EQ(2u, parent->children().size()); + EXPECT_EQ(surface1.get(), parent->children()[0]); + EXPECT_EQ(surface2.get(), parent->children()[1]); sub_surface2->PlaceAbove(parent.get()); sub_surface1->PlaceAbove(non_sibling_surface.get()); // Invalid @@ -55,14 +55,14 @@ // Nothing should have changed as Commit() is required for new stacking // order to take effect. - EXPECT_EQ(surface1.get(), parent->child_at(0)); - EXPECT_EQ(surface2.get(), parent->child_at(1)); + EXPECT_EQ(surface1.get(), parent->children()[0]); + EXPECT_EQ(surface2.get(), parent->children()[1]); parent->Commit(); // surface1 should now be stacked above surface2. - EXPECT_EQ(surface2.get(), parent->child_at(0)); - EXPECT_EQ(surface1.get(), parent->child_at(1)); + EXPECT_EQ(surface2.get(), parent->children()[0]); + EXPECT_EQ(surface1.get(), parent->children()[1]); } TEST_F(SubSurfaceTest, PlaceBelow) { @@ -75,9 +75,9 @@ scoped_ptr<SubSurface> sub_surface2( new SubSurface(surface2.get(), parent.get())); - ASSERT_EQ(2, parent->child_count()); - EXPECT_EQ(surface1.get(), parent->child_at(0)); - EXPECT_EQ(surface2.get(), parent->child_at(1)); + ASSERT_EQ(2u, parent->children().size()); + EXPECT_EQ(surface1.get(), parent->children()[0]); + EXPECT_EQ(surface2.get(), parent->children()[1]); sub_surface2->PlaceBelow(parent.get()); // Invalid sub_surface2->PlaceBelow(non_sibling_surface.get()); // Invalid @@ -86,14 +86,14 @@ // Nothing should have changed as Commit() is required for new stacking // order to take effect. - EXPECT_EQ(surface1.get(), parent->child_at(0)); - EXPECT_EQ(surface2.get(), parent->child_at(1)); + EXPECT_EQ(surface1.get(), parent->children()[0]); + EXPECT_EQ(surface2.get(), parent->children()[1]); parent->Commit(); // surface1 should now be stacked above surface2. - EXPECT_EQ(surface2.get(), parent->child_at(0)); - EXPECT_EQ(surface1.get(), parent->child_at(1)); + EXPECT_EQ(surface2.get(), parent->children()[0]); + EXPECT_EQ(surface1.get(), parent->children()[1]); } TEST_F(SubSurfaceTest, SetCommitBehavior) {
diff --git a/components/exo/surface.cc b/components/exo/surface.cc index 83f5972..717812c 100644 --- a/components/exo/surface.cc +++ b/components/exo/surface.cc
@@ -12,6 +12,9 @@ #include "components/exo/buffer.h" #include "components/exo/surface_delegate.h" #include "components/exo/surface_observer.h" +#include "ui/aura/window_delegate.h" +#include "ui/base/cursor/cursor.h" +#include "ui/base/hit_test.h" #include "ui/compositor/layer.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -35,21 +38,59 @@ return FindListEntry(list, key) != list.end(); } +// A window delegate which does nothing. Used to create a window that +// is an event target, but do nothing. +class EmptyWindowDelegate : public aura::WindowDelegate { + public: + EmptyWindowDelegate() {} + ~EmptyWindowDelegate() override {} + + // Overridden from aura::WindowDelegate: + gfx::Size GetMinimumSize() const override { return gfx::Size(); } + gfx::Size GetMaximumSize() const override { return gfx::Size(); } + void OnBoundsChanged(const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override {} + gfx::NativeCursor GetCursor(const gfx::Point& point) override { + return gfx::kNullCursor; + } + int GetNonClientComponent(const gfx::Point& point) const override { + return HTNOWHERE; + } + bool ShouldDescendIntoChildForEventHandling( + aura::Window* child, + const gfx::Point& location) override { + return false; + } + bool CanFocus() override { return true; } + void OnCaptureLost() override {} + void OnPaint(const ui::PaintContext& context) override {} + void OnDeviceScaleFactorChanged(float device_scale_factor) override {} + void OnWindowDestroying(aura::Window* window) override {} + void OnWindowDestroyed(aura::Window* window) override { delete this; } + void OnWindowTargetVisibilityChanged(bool visible) override {} + bool HasHitTestMask() const override { return false; } + void GetHitTestMask(gfx::Path* mask) const override {} + + private: + DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate); +}; + } // namespace //////////////////////////////////////////////////////////////////////////////// // Surface, public: Surface::Surface() - : has_pending_contents_(false), + : aura::Window(new EmptyWindowDelegate), + has_pending_contents_(false), needs_commit_surface_hierarchy_(false), update_contents_after_successful_compositing_(false), compositor_(nullptr), delegate_(nullptr) { - SetLayer(new ui::Layer(ui::LAYER_SOLID_COLOR)); - set_owned_by_client(); - SetVisible(false); - SetEnabled(false); + SetType(ui::wm::WINDOW_TYPE_CONTROL); + Init(ui::LAYER_SOLID_COLOR); + set_owned_by_parent(false); + SetName("ExoSurface"); } Surface::~Surface() { @@ -74,7 +115,6 @@ has_pending_contents_ = true; pending_buffer_ = buffer ? buffer->AsWeakPtr() : base::WeakPtr<Buffer>(); - PreferredSizeChanged(); } void Surface::Damage(const gfx::Rect& damage) { @@ -101,10 +141,9 @@ sub_surface->AsTracedValue()); DCHECK(!sub_surface->parent()); - DCHECK(!sub_surface->visible()); - DCHECK(!sub_surface->enabled()); + DCHECK(!sub_surface->IsVisible()); DCHECK(sub_surface->bounds().origin() == gfx::Point()); - AddChildView(sub_surface); + AddChild(sub_surface); DCHECK(!ListContainsEntry(pending_sub_surfaces_, sub_surface)); pending_sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point())); @@ -114,7 +153,7 @@ TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface", sub_surface->AsTracedValue()); - RemoveChildView(sub_surface); + RemoveChild(sub_surface); DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface)); pending_sub_surfaces_.erase( @@ -247,10 +286,10 @@ frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_); } - // Synchronize view hierarchy. This will position and update the stacking + // Synchronize window hierarchy. This will position and update the stacking // order of all sub-surfaces after committing all pending state of sub-surface // descendants. - int index = 0; + aura::Window* stacking_target = nullptr; for (auto& sub_surface_entry : pending_sub_surfaces_) { Surface* sub_surface = sub_surface_entry.first; @@ -260,20 +299,28 @@ sub_surface->CommitSurfaceHierarchy(); // Enable/disable sub-surface based on if it has contents. - sub_surface->SetVisible(sub_surface->has_contents()); - sub_surface->SetEnabled(sub_surface->has_contents()); + if (sub_surface->has_contents()) + sub_surface->Show(); + else + sub_surface->Hide(); // Move sub-surface to its new position in the stack. - DCHECK_LT(index, child_count()); - ReorderChildView(sub_surface, index); + if (stacking_target) + StackChildAbove(sub_surface, stacking_target); + + // Stack next sub-surface above this sub-surface. + stacking_target = sub_surface; // Update sub-surface position relative to surface origin. - sub_surface->SetPosition(sub_surface_entry.second); - - ++index; + sub_surface->SetBounds( + gfx::Rect(sub_surface_entry.second, sub_surface->layer()->size())); } } +gfx::Size Surface::GetPreferredSize() const { + return pending_buffer_ ? pending_buffer_->GetSize() : layer()->size(); +} + bool Surface::IsSynchronized() const { return delegate_ ? delegate_->IsSurfaceSynchronized() : false; } @@ -307,13 +354,6 @@ } //////////////////////////////////////////////////////////////////////////////// -// views::Views overrides: - -gfx::Size Surface::GetPreferredSize() const { - return pending_buffer_ ? pending_buffer_->GetSize() : layer()->size(); -} - -//////////////////////////////////////////////////////////////////////////////// // ui::CompositorObserver overrides: void Surface::OnCompositingDidCommit(ui::Compositor* compositor) {
diff --git a/components/exo/surface.h b/components/exo/surface.h index d21b3763..596fc5e 100644 --- a/components/exo/surface.h +++ b/components/exo/surface.h
@@ -13,9 +13,9 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "third_party/skia/include/core/SkRegion.h" +#include "ui/aura/window.h" #include "ui/compositor/compositor_observer.h" #include "ui/gfx/geometry/rect.h" -#include "ui/views/view.h" namespace base { namespace trace_event { @@ -30,7 +30,7 @@ // This class represents a rectangular area that is displayed on the screen. // It has a location, size and pixel contents. -class Surface : public views::View, public ui::CompositorObserver { +class Surface : public aura::Window, public ui::CompositorObserver { public: Surface(); ~Surface() override; @@ -74,6 +74,9 @@ // Returns true if surface is in synchronized mode. bool IsSynchronized() const; + // Returns the preferred size of surface. + gfx::Size GetPreferredSize() const; + // Set the surface delegate. void SetSurfaceDelegate(SurfaceDelegate* delegate); @@ -91,9 +94,6 @@ bool HasPendingDamageForTesting() const { return !pending_damage_.IsEmpty(); } - // Overridden from views::View: - gfx::Size GetPreferredSize() const override; - // Overridden from ui::CompositorObserver: void OnCompositingDidCommit(ui::Compositor* compositor) override; void OnCompositingStarted(ui::Compositor* compositor,
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn index 67d6d63..f69909b6 100644 --- a/components/exo/wayland/BUILD.gn +++ b/components/exo/wayland/BUILD.gn
@@ -35,6 +35,8 @@ deps = [ ":wayland", + "//base", + "//components/exo", "//testing/gtest", "//third_party/wayland:wayland_client", ]
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index 2a6bed3e..a6728467 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -586,7 +586,7 @@ wl_resource* resource, wl_resource* seat_resource, uint32_t serial) { - NOTIMPLEMENTED(); + GetUserDataAs<ShellSurface>(resource)->Move(); } void shell_surface_resize(wl_client* client, @@ -645,7 +645,7 @@ void shell_surface_set_class(wl_client* client, wl_resource* resource, const char* clazz) { - NOTIMPLEMENTED(); + GetUserDataAs<ShellSurface>(resource)->SetApplicationId(clazz); } const struct wl_shell_surface_interface shell_surface_implementation = {
diff --git a/components/html_viewer/global_state.cc b/components/html_viewer/global_state.cc index 4bbf4db..2a2261b 100644 --- a/components/html_viewer/global_state.cc +++ b/components/html_viewer/global_state.cc
@@ -9,6 +9,8 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/logging.h" +#include "cc/blink/web_layer_impl.h" +#include "cc/layers/layer_settings.h" #include "components/html_viewer/blink_platform_impl.h" #include "components/html_viewer/blink_settings_impl.h" #include "components/html_viewer/media_factory.h" @@ -128,6 +130,12 @@ gpu_service_->GetGpuInfo(base::Bind(&GlobalState::GetGpuInfoCallback, base::Unretained(this))); + // Use new animation system (cc::AnimationHost). + cc::LayerSettings layer_settings; + layer_settings.use_compositor_animation_timelines = true; + cc_blink::WebLayerImpl::SetLayerSettings(layer_settings); + blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(true); + renderer_scheduler_ = scheduler::RendererScheduler::Create(); blink_platform_.reset( new BlinkPlatformImpl(this, app_, renderer_scheduler_.get()));
diff --git a/components/html_viewer/web_layer_tree_view_impl.cc b/components/html_viewer/web_layer_tree_view_impl.cc index c379bc9b..2f793b8 100644 --- a/components/html_viewer/web_layer_tree_view_impl.cc +++ b/components/html_viewer/web_layer_tree_view_impl.cc
@@ -41,6 +41,9 @@ // to keep content always crisp when possible. settings.layer_transforms_should_scale_layer_contents = true; + // Use new animation system (cc::AnimationHost). + settings.use_compositor_animation_timelines = true; + // TODO(rjkroege): Not having a shared tile transport breaks // software compositing. Add bitmap transport support. cc::SharedBitmapManager* shared_bitmap_manager = nullptr;
diff --git a/components/mus/public/cpp/lib/in_flight_change.cc b/components/mus/public/cpp/lib/in_flight_change.cc index d6017c8..002ee3f 100644 --- a/components/mus/public/cpp/lib/in_flight_change.cc +++ b/components/mus/public/cpp/lib/in_flight_change.cc
@@ -85,4 +85,20 @@ .LocalSetSharedProperty(property_name_, revert_value_.Pass()); } +// InFlightVisibleChange ------------------------------------------------------- + +InFlightVisibleChange::InFlightVisibleChange(Window* window, + bool revert_value) + : InFlightChange(window, ChangeType::VISIBLE), + revert_visible_(revert_value) {} + +void InFlightVisibleChange::SetRevertValueFrom(const InFlightChange& change) { + revert_visible_ = + static_cast<const InFlightVisibleChange&>(change).revert_visible_; +} + +void InFlightVisibleChange::Revert() { + WindowPrivate(window()).LocalSetVisible(revert_visible_); +} + } // namespace mus
diff --git a/components/mus/public/cpp/lib/in_flight_change.h b/components/mus/public/cpp/lib/in_flight_change.h index 3dc42a7..33d0417 100644 --- a/components/mus/public/cpp/lib/in_flight_change.h +++ b/components/mus/public/cpp/lib/in_flight_change.h
@@ -23,7 +23,8 @@ DELETE_WINDOW, NEW_WINDOW, PROPERTY, - REMOVE_TRANSIENT_WINDOW_FROM_PARENT + REMOVE_TRANSIENT_WINDOW_FROM_PARENT, + VISIBLE, }; // InFlightChange is used to track function calls to the server and take the @@ -130,6 +131,21 @@ DISALLOW_COPY_AND_ASSIGN(InFlightPropertyChange); }; +class InFlightVisibleChange : public InFlightChange { + public: + InFlightVisibleChange(Window* window, const bool revert_value); + + // InFlightChange: + void SetRevertValueFrom(const InFlightChange& change) override; + void Revert() override; + + private: + Window* window_; + bool revert_visible_; + + DISALLOW_COPY_AND_ASSIGN(InFlightVisibleChange); +}; + } // namespace mus #endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc index 8dffc7f5..aa77867d 100644 --- a/components/mus/public/cpp/lib/window.cc +++ b/components/mus/public/cpp/lib/window.cc
@@ -206,7 +206,7 @@ return; if (connection_) - tree_client()->SetVisible(id_, value); + tree_client()->SetVisible(this, value); LocalSetVisible(value); }
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc index 163f1a3..2b094e9 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.cc +++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -222,9 +222,11 @@ tree_->SetCanFocus(window_id, can_focus); } -void WindowTreeClientImpl::SetVisible(Id window_id, bool visible) { +void WindowTreeClientImpl::SetVisible(Window* window, bool visible) { DCHECK(tree_); - tree_->SetWindowVisibility(window_id, visible, ActionCompletedCallback()); + const uint32_t change_id = ScheduleInFlightChange( + make_scoped_ptr(new InFlightVisibleChange(window, !visible))); + tree_->SetWindowVisibility(change_id, window->id(), visible); } void WindowTreeClientImpl::SetProperty(Window* window, @@ -535,12 +537,15 @@ void WindowTreeClientImpl::OnWindowVisibilityChanged(Id window_id, bool visible) { - // TODO(sky): there is a race condition here. If this client and another - // client change the visibility at the same time the wrong value may be set. - // Deal with this some how. Window* window = GetWindowById(window_id); - if (window) - WindowPrivate(window).LocalSetVisible(visible); + if (!window) + return; + + InFlightVisibleChange new_change(window, visible); + if (ApplyServerChangeToExistingInFlightChange(new_change)) + return; + + WindowPrivate(window).LocalSetVisible(visible); } void WindowTreeClientImpl::OnWindowDrawnStateChanged(Id window_id, bool drawn) { @@ -655,13 +660,8 @@ //////////////////////////////////////////////////////////////////////////////// // WindowTreeClientImpl, private: -void WindowTreeClientImpl::OnActionCompleted(bool success) { - if (!change_acked_callback_.is_null()) - change_acked_callback_.Run(); -} - mojo::Callback<void(bool)> WindowTreeClientImpl::ActionCompletedCallback() { - return [this](bool success) { OnActionCompleted(success); }; + return [this](bool success) {}; } } // namespace mus
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h index 16caa4c..af224db 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.h +++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -67,7 +67,7 @@ void SetClientArea(Id window_id, const gfx::Insets& client_area); void SetFocus(Id window_id); void SetCanFocus(Id window_id, bool can_focus); - void SetVisible(Id window_id, bool visible); + void SetVisible(Window* window, bool visible); void SetProperty(Window* window, const std::string& name, mojo::Array<uint8_t> data); @@ -86,11 +86,6 @@ mojo::InterfaceRequest<mojom::Surface> surface, mojom::SurfaceClientPtr client); - void set_change_acked_callback(const mojo::Callback<void(void)>& callback) { - change_acked_callback_ = callback; - } - void ClearChangeAckedCallback() { change_acked_callback_.reset(); } - // Start/stop tracking windows. While tracked, they can be retrieved via // WindowTreeConnection::GetWindowById. void AddWindow(Window* window); @@ -183,8 +178,6 @@ const mojo::String& name, mojo::Array<uint8_t> transit_data) override; - void OnActionCompleted(bool success); - mojo::Callback<void(bool)> ActionCompletedCallback(); // This is set once and only once when we get OnEmbed(). It gives the unique @@ -198,8 +191,6 @@ uint32_t next_change_id_; InFlightMap in_flight_map_; - mojo::Callback<void(void)> change_acked_callback_; - WindowTreeDelegate* delegate_; WindowManagerDelegate* window_manager_delegate_;
diff --git a/components/mus/public/cpp/tests/test_window_tree.cc b/components/mus/public/cpp/tests/test_window_tree.cc index 46c64511..1eff074 100644 --- a/components/mus/public/cpp/tests/test_window_tree.cc +++ b/components/mus/public/cpp/tests/test_window_tree.cc
@@ -37,10 +37,12 @@ void TestWindowTree::SetClientArea(uint32_t window_id, mojo::InsetsPtr insets) { } -void TestWindowTree::SetWindowVisibility( - uint32_t window_id, - bool visible, - const SetWindowVisibilityCallback& callback) {} +void TestWindowTree::SetWindowVisibility(uint32_t change_id, + uint32_t window_id, + bool visible) { + got_change_ = true; + change_id_ = change_id; +} void TestWindowTree::SetWindowProperty(uint32_t change_id, uint32_t window_id,
diff --git a/components/mus/public/cpp/tests/test_window_tree.h b/components/mus/public/cpp/tests/test_window_tree.h index 6db82a4..80bdec5 100644 --- a/components/mus/public/cpp/tests/test_window_tree.h +++ b/components/mus/public/cpp/tests/test_window_tree.h
@@ -32,10 +32,9 @@ uint32_t window_id, mojo::RectPtr bounds) override; void SetClientArea(uint32_t window_id, mojo::InsetsPtr insets) override; - void SetWindowVisibility( - uint32_t window_id, - bool visible, - const SetWindowVisibilityCallback& callback) override; + void SetWindowVisibility(uint32_t change_id, + uint32_t window_id, + bool visible) override; void SetWindowProperty(uint32_t change_id, uint32_t window_id, const mojo::String& name,
diff --git a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc index 2b92cbb4..11f54962 100644 --- a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc +++ b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
@@ -228,4 +228,52 @@ EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo")); } +// Verifies visible is reverted if the server replied that the change failed. +TEST_F(WindowTreeClientImplTest, SetVisibleFailed) { + WindowTreeSetup setup; + Window* root = setup.window_tree_connection()->GetRoot(); + ASSERT_TRUE(root); + const bool original_visible = root->visible(); + const bool new_visible = !original_visible; + ASSERT_NE(new_visible, root->visible()); + root->SetVisible(new_visible); + uint32_t change_id; + ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id)); + setup.window_tree_client()->OnChangeCompleted(change_id, false); + EXPECT_EQ(original_visible, root->visible()); +} + +// Simulates a visible change, and while the visible change is in flight the +// server replies with a new visible and the original visible change fails. +TEST_F(WindowTreeClientImplTest, SetVisibleFailedWithPendingChange) { + WindowTreeSetup setup; + Window* root = setup.window_tree_connection()->GetRoot(); + ASSERT_TRUE(root); + const bool original_visible = root->visible(); + const bool new_visible = !original_visible; + ASSERT_NE(new_visible, root->visible()); + root->SetVisible(new_visible); + EXPECT_EQ(new_visible, root->visible()); + uint32_t change_id; + ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id)); + + // Simulate the server responding with a visible change. + const bool server_changed_visible = !new_visible; + setup.window_tree_client()->OnWindowVisibilityChanged(root->id(), + server_changed_visible); + + // This shouldn't trigger visible changing yet. + EXPECT_EQ(new_visible, root->visible()); + + // Tell the client the change failed, which should trigger failing to the + // most recent visible from server. + setup.window_tree_client()->OnChangeCompleted(change_id, false); + EXPECT_EQ(server_changed_visible, root->visible()); + + // Simulate server changing back to original visible. Should take immediately. + setup.window_tree_client()->OnWindowVisibilityChanged(root->id(), + original_visible); + EXPECT_EQ(original_visible, root->visible()); +} + } // namespace mus
diff --git a/components/mus/public/interfaces/BUILD.gn b/components/mus/public/interfaces/BUILD.gn index 899401a..cd27ea1 100644 --- a/components/mus/public/interfaces/BUILD.gn +++ b/components/mus/public/interfaces/BUILD.gn
@@ -6,6 +6,7 @@ mojom("interfaces") { sources = [ + "accelerator_registrar.mojom", "command_buffer.mojom", "compositor_frame.mojom", "gpu.mojom",
diff --git a/components/mus/public/interfaces/accelerator_registrar.mojom b/components/mus/public/interfaces/accelerator_registrar.mojom new file mode 100644 index 0000000..ba210ec --- /dev/null +++ b/components/mus/public/interfaces/accelerator_registrar.mojom
@@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mus.mojom; + +import "components/mus/public/interfaces/input_event_matcher.mojom"; +import "components/mus/public/interfaces/input_events.mojom"; + +interface AcceleratorHandler { + OnAccelerator(uint32 id, Event event); +}; + +interface AcceleratorRegistrar { + // The AcceleratorHandler is responsible for handling all the accelerators + // registered from this AcceleratorRegistrar connection. + SetHandler(AcceleratorHandler handler); + + // An AcceleratorHandler must be set before accelerators can be added. + AddAccelerator(uint32 id, EventMatcher matcher) => (bool success); + RemoveAccelerator(uint32 id); +};
diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom index f08a1d0d..0d2bd2e 100644 --- a/components/mus/public/interfaces/window_manager.mojom +++ b/components/mus/public/interfaces/window_manager.mojom
@@ -12,6 +12,10 @@ array<Display> displays; mojo.Insets normal_client_area_insets; mojo.Insets maximized_client_area_insets; + // Max width needed to display the buttons on the title bar. The buttons are + // aligned to the trailing edge of the titlebar. + // TODO(sky): this API is very narrow, and assumes a particular config. + uint32 max_title_bar_button_width; }; // Represents a core interface that should be implemented by any window manager
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom index 455929a..9c64bb8 100644 --- a/components/mus/public/interfaces/window_tree.mojom +++ b/components/mus/public/interfaces/window_tree.mojom
@@ -106,7 +106,7 @@ // Sets the visibility of the specified window to |visible|. Connections are // allowed to change the visibility of any window they have created, as well // as any of their roots. - SetWindowVisibility(uint32 window_id, bool visible) => (bool success); + SetWindowVisibility(uint32 change_id, uint32 window_id, bool visible); // Sets an individual named property. Setting an individual property to null // deletes the property.
diff --git a/components/mus/public/interfaces/window_tree_host.mojom b/components/mus/public/interfaces/window_tree_host.mojom index 3209bdab..32cd0af 100644 --- a/components/mus/public/interfaces/window_tree_host.mojom +++ b/components/mus/public/interfaces/window_tree_host.mojom
@@ -24,8 +24,10 @@ // Add and remove accelerators. When accelerators are registered the // WindowTreeHostClient receives the event via OnAccelerator() rather than the // target window. The id is defined by the client and can be used to more - // easily identify the accelerator's action. - AddAccelerator(uint32 id, EventMatcher matcher); + // easily identify the accelerator's action. If an accelerator with the same + // id or the same matcher already exists, then the accelerator is not added, + // and returns false. + AddAccelerator(uint32 id, EventMatcher matcher) => (bool success); RemoveAccelerator(uint32 id); // Enables (or disables) child windows of |window_id| to be activated.
diff --git a/components/mus/surfaces/surfaces_scheduler.cc b/components/mus/surfaces/surfaces_scheduler.cc index 1f25df2..f324db7 100644 --- a/components/mus/surfaces/surfaces_scheduler.cc +++ b/components/mus/surfaces/surfaces_scheduler.cc
@@ -77,8 +77,6 @@ return cc::DRAW_SUCCESS; } -void SurfacesScheduler::ScheduledActionAnimate() {} - void SurfacesScheduler::ScheduledActionCommit() { scheduler_->NotifyReadyToActivate(); }
diff --git a/components/mus/surfaces/surfaces_scheduler.h b/components/mus/surfaces/surfaces_scheduler.h index 24ceac5..93ba113 100644 --- a/components/mus/surfaces/surfaces_scheduler.h +++ b/components/mus/surfaces/surfaces_scheduler.h
@@ -37,7 +37,6 @@ const cc::BeginFrameArgs& args) override; cc::DrawResult ScheduledActionDrawAndSwapIfPossible() override; cc::DrawResult ScheduledActionDrawAndSwapForced() override; - void ScheduledActionAnimate() override; void ScheduledActionCommit() override; void ScheduledActionActivateSyncTree() override; void ScheduledActionBeginOutputSurfaceCreation() override;
diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc index c9f71de..384f9ba8 100644 --- a/components/mus/ws/event_dispatcher.cc +++ b/components/mus/ws/event_dispatcher.cc
@@ -109,7 +109,6 @@ return true; } -#if !defined(NDEBUG) bool Equals(const EventMatcher& matcher) const { return fields_to_match_ == matcher.fields_to_match_ && event_type_ == matcher.event_type_ && @@ -118,7 +117,6 @@ pointer_kind_ == matcher.pointer_kind_ && pointer_region_ == matcher.pointer_region_; } -#endif private: enum MatchFields { @@ -153,16 +151,16 @@ } } -void EventDispatcher::AddAccelerator(uint32_t id, +bool EventDispatcher::AddAccelerator(uint32_t id, mojom::EventMatcherPtr event_matcher) { EventMatcher matcher(*event_matcher); -#if !defined(NDEBUG) + // If an accelerator with the same id or matcher already exists, then abort. for (const auto& pair : accelerators_) { - DCHECK_NE(pair.first, id); - DCHECK(!matcher.Equals(pair.second)); + if (pair.first == id || matcher.Equals(pair.second)) + return false; } -#endif accelerators_.insert(Entry(id, matcher)); + return true; } void EventDispatcher::RemoveAccelerator(uint32_t id) {
diff --git a/components/mus/ws/event_dispatcher.h b/components/mus/ws/event_dispatcher.h index bbd2bad..a6ffd62 100644 --- a/components/mus/ws/event_dispatcher.h +++ b/components/mus/ws/event_dispatcher.h
@@ -33,7 +33,10 @@ void set_surface_id(cc::SurfaceId surface_id) { surface_id_ = surface_id; } - void AddAccelerator(uint32_t id, mojom::EventMatcherPtr event_matcher); + // Adds an accelerator with the given id and event-matcher. If an accelerator + // already exists with the same id or the same matcher, then the accelerator + // is not added. Returns whether adding the accelerator was successful or not. + bool AddAccelerator(uint32_t id, mojom::EventMatcherPtr event_matcher); void RemoveAccelerator(uint32_t id); void OnEvent(mojom::EventPtr event);
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc index 00513d6..d837dbc 100644 --- a/components/mus/ws/event_dispatcher_unittest.cc +++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -166,6 +166,42 @@ EXPECT_EQ(gfx::Point(10, 15), dispatched_mouse_event->location()); } +TEST(EventDispatcherTest, AcceleratorBasic) { + TestEventDispatcherDelegate event_dispatcher_delegate(nullptr); + EventDispatcher dispatcher(&event_dispatcher_delegate); + uint32_t accelerator_1 = 1; + mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher( + mus::mojom::KEYBOARD_CODE_W, mus::mojom::EVENT_FLAGS_CONTROL_DOWN); + EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_1, matcher.Pass())); + + uint32_t accelerator_2 = 2; + matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_N, + mus::mojom::EVENT_FLAGS_NONE); + EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass())); + + // Attempting to add a new accelerator with the same id should fail. + matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T, + mus::mojom::EVENT_FLAGS_NONE); + EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass())); + + // Adding the accelerator with the same id should succeed once the existing + // accelerator is removed. + dispatcher.RemoveAccelerator(accelerator_2); + matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T, + mus::mojom::EVENT_FLAGS_NONE); + EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, matcher.Pass())); + + // Attempting to add an accelerator with the same matcher should fail. + uint32_t accelerator_3 = 3; + matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T, + mus::mojom::EVENT_FLAGS_NONE); + EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_3, matcher.Pass())); + + matcher = mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_T, + mus::mojom::EVENT_FLAGS_CONTROL_DOWN); + EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_3, matcher.Pass())); +} + TEST(EventDispatcherTest, EventMatching) { TestServerWindowDelegate window_delegate; ServerWindow root(&window_delegate, WindowId(1, 2));
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc index 70613fc..3895571 100644 --- a/components/mus/ws/window_tree_apptest.cc +++ b/components/mus/ws/window_tree_apptest.cc
@@ -134,15 +134,6 @@ run_loop.Run(); } -bool SetWindowVisibility(WindowTree* ws, Id window_id, bool visible) { - base::RunLoop run_loop; - bool result = false; - ws->SetWindowVisibility(window_id, visible, - base::Bind(&BoolResultCallback, &run_loop, &result)); - run_loop.Run(); - return result; -} - // Utility functions ----------------------------------------------------------- const Id kNullParentId = 0; @@ -257,6 +248,12 @@ return WaitForChangeCompleted(change_id); } + bool SetWindowVisibility(Id window_id, bool visible) { + const uint32_t change_id = GetAndAdvanceChangeId(); + tree()->SetWindowVisibility(change_id, window_id, visible); + return WaitForChangeCompleted(change_id); + } + private: // Used when running a nested MessageLoop. struct WaitState { @@ -808,15 +805,15 @@ // 1,2->1,11. Id window_1_2 = ws_client1()->NewWindow(2); ASSERT_TRUE(window_1_2); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_2, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_2, true)); Id window_1_11 = ws_client1()->NewWindow(11); ASSERT_TRUE(window_1_11); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_11, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_11, true)); ASSERT_TRUE(AddWindow(ws1(), window_1_2, window_1_11)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, true)); ASSERT_TRUE(ws_client2()->WaitForAllMessages()); changes2()->clear(); @@ -855,7 +852,7 @@ // 1,1->1,2->1,11->1,111. Id window_1_111 = ws_client1()->NewWindow(111); ASSERT_TRUE(window_1_111); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_111, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_111, true)); { changes2()->clear(); ASSERT_TRUE(AddWindow(ws1(), window_1_11, window_1_111)); @@ -1361,8 +1358,8 @@ } // Show all the windows. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true)); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_2, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_2, true)); { std::vector<TestWindow> windows; GetWindowTree(ws1(), root_window_id(), &windows); @@ -1376,7 +1373,7 @@ } // Hide 1. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, false)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, false)); { std::vector<TestWindow> windows; GetWindowTree(ws1(), window_1_1, &windows); @@ -1401,7 +1398,7 @@ } // Show 1. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, true)); { std::vector<TestWindow> windows; GetWindowTree(ws1(), window_1_1, &windows); @@ -1420,10 +1417,10 @@ // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root. Id window_1_1 = ws_client1()->NewWindow(1); ASSERT_TRUE(window_1_1); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, true)); Id window_1_2 = ws_client1()->NewWindow(2); ASSERT_TRUE(window_1_2); - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_2, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_2, true)); ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1)); ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2)); @@ -1433,13 +1430,13 @@ // Add 2,3 as a child of 1,2. Id window_2_3 = ws_client2()->NewWindow(3); ASSERT_TRUE(window_2_3); - ASSERT_TRUE(SetWindowVisibility(ws2(), window_2_3, true)); + ASSERT_TRUE(ws_client2()->SetWindowVisibility(window_2_3, true)); ASSERT_TRUE(AddWindow(ws2(), window_1_2, window_2_3)); ASSERT_TRUE(ws_client1()->WaitForAllMessages()); changes2()->clear(); // Hide 1,2 from connection 1. Connection 2 should see this. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_2, false)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_2, false)); { ws_client2_->WaitForChangeCount(1); EXPECT_EQ( @@ -1449,7 +1446,7 @@ changes1()->clear(); // Show 1,2 from connection 2, connection 1 should be notified. - ASSERT_TRUE(SetWindowVisibility(ws2(), window_1_2, true)); + ASSERT_TRUE(ws_client2()->SetWindowVisibility(window_1_2, true)); { ws_client1_->WaitForChangeCount(1); EXPECT_EQ( @@ -1459,7 +1456,7 @@ changes2()->clear(); // Hide 1,1, connection 2 should be told the draw state changed. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, false)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, false)); { ws_client2_->WaitForChangeCount(1); EXPECT_EQ( @@ -1469,7 +1466,7 @@ changes2()->clear(); // Show 1,1 from connection 1. Connection 2 should see this. - ASSERT_TRUE(SetWindowVisibility(ws1(), window_1_1, true)); + ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_1, true)); { ws_client2_->WaitForChangeCount(1); EXPECT_EQ( @@ -1479,7 +1476,7 @@ // Change visibility of 2,3, connection 1 should see this. changes1()->clear(); - ASSERT_TRUE(SetWindowVisibility(ws2(), window_2_3, false)); + ASSERT_TRUE(ws_client2()->SetWindowVisibility(window_2_3, false)); { ws_client1_->WaitForChangeCount(1); EXPECT_EQ(
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc index 16c3176d6..8214b692 100644 --- a/components/mus/ws/window_tree_host_impl.cc +++ b/components/mus/ws/window_tree_host_impl.cc
@@ -139,9 +139,12 @@ display_manager_->SetTitle(title.To<base::string16>()); } -void WindowTreeHostImpl::AddAccelerator(uint32_t id, - mojom::EventMatcherPtr event_matcher) { - event_dispatcher_.AddAccelerator(id, event_matcher.Pass()); +void WindowTreeHostImpl::AddAccelerator( + uint32_t id, + mojom::EventMatcherPtr event_matcher, + const AddAcceleratorCallback& callback) { + bool success = event_dispatcher_.AddAccelerator(id, event_matcher.Pass()); + callback.Run(success); } void WindowTreeHostImpl::RemoveAccelerator(uint32_t id) {
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h index ae23e2c1..3ed61fe 100644 --- a/components/mus/ws/window_tree_host_impl.h +++ b/components/mus/ws/window_tree_host_impl.h
@@ -97,7 +97,8 @@ void SetSize(mojo::SizePtr size) override; void SetTitle(const mojo::String& title) override; void AddAccelerator(uint32_t id, - mojom::EventMatcherPtr event_matcher) override; + mojom::EventMatcherPtr event_matcher, + const AddAcceleratorCallback& callback) override; void RemoveAccelerator(uint32_t id) override; void AddActivationParent(uint32_t window_id) override; void RemoveActivationParent(uint32_t window_id) override;
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc index 18edf8a..38c9305 100644 --- a/components/mus/ws/window_tree_impl.cc +++ b/components/mus/ws/window_tree_impl.cc
@@ -741,11 +741,12 @@ client_->OnChangeCompleted(change_id, success); } -void WindowTreeImpl::SetWindowVisibility(Id transport_window_id, - bool visible, - const Callback<void(bool)>& callback) { - callback.Run(SetWindowVisibility(WindowIdFromTransportId(transport_window_id), - visible)); +void WindowTreeImpl::SetWindowVisibility(uint32_t change_id, + Id transport_window_id, + bool visible) { + client_->OnChangeCompleted( + change_id, SetWindowVisibility( + WindowIdFromTransportId(transport_window_id), visible)); } void WindowTreeImpl::SetWindowProperty(uint32_t change_id,
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h index e17d0d0..0a92f4f 100644 --- a/components/mus/ws/window_tree_impl.h +++ b/components/mus/ws/window_tree_impl.h
@@ -219,9 +219,9 @@ void SetWindowBounds(uint32_t change_id, Id window_id, mojo::RectPtr bounds) override; - void SetWindowVisibility(Id window_id, - bool visible, - const mojo::Callback<void(bool)>& callback) override; + void SetWindowVisibility(uint32_t change_id, + Id window_id, + bool visible) override; void SetWindowProperty(uint32_t change_id, Id window_id, const mojo::String& name,
diff --git a/components/nacl/BUILD.gn b/components/nacl/BUILD.gn index 1addcfc..ad200c93 100644 --- a/components/nacl/BUILD.gn +++ b/components/nacl/BUILD.gn
@@ -38,6 +38,7 @@ "//ppapi/c", "//ppapi/proxy:ipc", "//ppapi/shared_impl", + "//sandbox", "//third_party/mojo/src/mojo/edk/system", ]
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc index 7a82df4..5b6cb44 100644 --- a/components/nacl/browser/nacl_process_host.cc +++ b/components/nacl/browser/nacl_process_host.cc
@@ -180,7 +180,7 @@ } #elif defined(OS_POSIX) bool ShouldUseZygote() override { return true; } - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN private:
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc index 20ed046..cf880745 100644 --- a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc +++ b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc
@@ -332,7 +332,7 @@ bool sandbox_is_initialized = content::InitializeSandbox( scoped_ptr<sandbox::bpf_dsl::Policy>( new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy()), - proc_fd.Pass()); + std::move(proc_fd)); if (!sandbox_is_initialized) return false; RunSandboxSanityChecks();
diff --git a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc index 3b3cf9d..e4d3c705 100644 --- a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc +++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
@@ -187,7 +187,7 @@ // will prevent its usage. #if defined(OS_NACL_NONSFI) CHECK(uses_nonsfi_mode); - layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(proc_fd_.Pass()); + layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(std::move(proc_fd_)); layer_two_is_nonsfi_ = true; #else CHECK(!uses_nonsfi_mode);
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc index 1757bf68..c7ee0a5 100644 --- a/components/omnibox/browser/history_url_provider.cc +++ b/components/omnibox/browser/history_url_provider.cc
@@ -461,7 +461,8 @@ AutocompleteProviderListener* listener) : HistoryProvider(AutocompleteProvider::TYPE_HISTORY_URL, client), listener_(listener), - params_(NULL) { + params_(NULL), + search_url_database_(OmniboxFieldTrial::HUPSearchDatabase()) { // Initialize the default HUP scoring params. OmniboxFieldTrial::GetDefaultHUPScoringParams(&scoring_params_); // Initialize HUP scoring params based on the current experiment. @@ -557,7 +558,7 @@ // Pass 2: Ask the history service to call us back on the history thread, // where we can read the full on-disk DB. - if (input.want_asynchronous_matches()) { + if (search_url_database_ && input.want_asynchronous_matches()) { done_ = false; params_ = params.release(); // This object will be destroyed in // QueryComplete() once we're done with it. @@ -712,35 +713,38 @@ // Get the matching URLs from the DB. params->matches.clear(); history::URLRows url_matches; - const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); - for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); - ++i) { - if (params->cancel_flag.IsSet()) - return; // Canceled in the middle of a query, give up. - // We only need kMaxMatches results in the end, but before we get there we - // need to promote lower-quality matches that are prefixes of higher-quality - // matches, and remove lower-quality redirects. So we ask for more results - // than we need, of every prefix type, in hopes this will give us far more - // than enough to work with. CullRedirects() will then reduce the list to - // the best kMaxMatches results. - db->AutocompleteForPrefix( - base::UTF16ToUTF8(i->prefix + params->input.text()), kMaxMatches * 2, - !backend, &url_matches); - for (history::URLRows::const_iterator j(url_matches.begin()); - j != url_matches.end(); ++j) { - const URLPrefix* best_prefix = URLPrefix::BestURLPrefix( - base::UTF8ToUTF16(j->url().spec()), base::string16()); - DCHECK(best_prefix); - params->matches.push_back(history::HistoryMatch( - *j, i->prefix.length(), !i->num_components, - i->num_components >= best_prefix->num_components)); + if (search_url_database_) { + const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); + for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); + ++i) { + if (params->cancel_flag.IsSet()) + return; // Canceled in the middle of a query, give up. + + // We only need kMaxMatches results in the end, but before we get there we + // need to promote lower-quality matches that are prefixes of higher- + // quality matches, and remove lower-quality redirects. So we ask for + // more results than we need, of every prefix type, in hopes this will + // give us far more than enough to work with. CullRedirects() will then + // reduce the list to the best kMaxMatches results. + db->AutocompleteForPrefix( + base::UTF16ToUTF8(i->prefix + params->input.text()), kMaxMatches * 2, + !backend, &url_matches); + for (history::URLRows::const_iterator j(url_matches.begin()); + j != url_matches.end(); ++j) { + const URLPrefix* best_prefix = URLPrefix::BestURLPrefix( + base::UTF8ToUTF16(j->url().spec()), base::string16()); + DCHECK(best_prefix); + params->matches.push_back(history::HistoryMatch( + *j, i->prefix.length(), !i->num_components, + i->num_components >= best_prefix->num_components)); + } } - } - // Create sorted list of suggestions. - CullPoorMatches(params); - SortAndDedupMatches(¶ms->matches); + // Create sorted list of suggestions. + CullPoorMatches(params); + SortAndDedupMatches(¶ms->matches); + } // Try to create a shorter suggestion from the best match. // We consider the what you typed match eligible for display when it's
diff --git a/components/omnibox/browser/history_url_provider.h b/components/omnibox/browser/history_url_provider.h index cf6a3b6..d7d67e8 100644 --- a/components/omnibox/browser/history_url_provider.h +++ b/components/omnibox/browser/history_url_provider.h
@@ -333,6 +333,15 @@ // keep this member is so we can set the cancel bit on it. HistoryURLProviderParams* params_; + // Whether to query the history URL database to match. Even if false, we + // still use the URL database to decide if the URL-what-you-typed was visited + // before or not. If false, the only possible result that HistoryURL provider + // can return is URL-what-you-typed. This variable is not part of params_ + // because it never changes after the HistoryURLProvider is initialized. + // It's used to aid the possible transition to get all URLs from history to + // be scored in the HistoryQuick provider only. + bool search_url_database_; + // Params controlling experimental behavior of this provider. HUPScoringParams scoring_params_;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 2d03ad8..50dc320 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -440,6 +440,13 @@ kHQPAlsoDoHUPLikeScoringRule) == "true"; } +bool OmniboxFieldTrial::HUPSearchDatabase() { + const std::string& value = variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kHUPSearchDatabaseRule); + return value.empty() || (value == "true"); +} + bool OmniboxFieldTrial::PreventUWYTDefaultForNonURLInputs() { return variations::GetVariationParamValue( kBundledExperimentFieldTrialName, @@ -503,6 +510,8 @@ const char OmniboxFieldTrial::kHQPNumTitleWordsRule[] = "HQPNumTitleWords"; const char OmniboxFieldTrial::kHQPAlsoDoHUPLikeScoringRule[] = "HQPAlsoDoHUPLikeScoring"; +const char OmniboxFieldTrial::kHUPSearchDatabaseRule[] = + "HUPSearchDatabase"; const char OmniboxFieldTrial::kPreventUWYTDefaultForNonURLInputsRule[] = "PreventUWYTDefaultForNonURLInputs"; const char OmniboxFieldTrial::kKeywordRequiresRegistryRule[] =
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 566b89f..2dcc254 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -303,8 +303,8 @@ static size_t HQPNumTitleWordsToAllow(); // --------------------------------------------------------- - // For the HQPAlsoDoHUPLikeScoring experiment that's part of the - // bundled omnibox field trial. + // For the replace HUP experiment that's part of the bundled omnibox field + // trial. // Returns whether HistoryQuick provider (HQP) should attempt to score // suggestions also with a HistoryURL-provider-like (HUP-like) mode, and @@ -312,6 +312,12 @@ // Returns false if the experiment isn't active. static bool HQPAlsoDoHUPLikeScoring(); + // Returns whether HistoryURL provider (HUP) should search its database for + // URLs and suggest them. If false, HistoryURL provider merely creates the + // URL-what-you-typed match when appropriate. Return true if the experiment + // isn't active. + static bool HUPSearchDatabase(); + // --------------------------------------------------------- // For the PreventUWYTDefaultForNonURLInputs experiment that's part of the // bundled omnibox field trial. @@ -367,6 +373,7 @@ static const char kHQPFixFewVisitsBugRule[]; static const char kHQPNumTitleWordsRule[]; static const char kHQPAlsoDoHUPLikeScoringRule[]; + static const char kHUPSearchDatabaseRule[]; static const char kPreventUWYTDefaultForNonURLInputsRule[]; static const char kKeywordRequiresRegistryRule[]; static const char kKeywordRequiresPrefixMatchRule[];
diff --git a/components/resources/components_scaled_resources.grd b/components/resources/components_scaled_resources.grd index 99ee83a..2cb4e4a7 100644 --- a/components/resources/components_scaled_resources.grd +++ b/components/resources/components_scaled_resources.grd
@@ -16,6 +16,7 @@ <structures fallback_to_low_resolution="true"> <part file="autofill_scaled_resources.grdp" /> <part file="crash_scaled_resources.grdp" /> + <part file="flags_ui_scaled_resources.grdp" /> <part file="omnibox_scaled_resources.grdp" /> <part file="version_ui_scaled_resources.grdp" /> </structures>
diff --git a/chrome/app/theme/default_100_percent/common/favicon_flags.png b/components/resources/default_100_percent/flags_ui/favicon_flags.png similarity index 100% rename from chrome/app/theme/default_100_percent/common/favicon_flags.png rename to components/resources/default_100_percent/flags_ui/favicon_flags.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_flags.png b/components/resources/default_200_percent/flags_ui/favicon_flags.png similarity index 100% rename from chrome/app/theme/default_200_percent/common/favicon_flags.png rename to components/resources/default_200_percent/flags_ui/favicon_flags.png Binary files differ
diff --git a/chrome/app/theme/default_300_percent/common/favicon_flags.png b/components/resources/default_300_percent/flags_ui/favicon_flags.png similarity index 100% rename from chrome/app/theme/default_300_percent/common/favicon_flags.png rename to components/resources/default_300_percent/flags_ui/favicon_flags.png Binary files differ
diff --git a/components/resources/flags_ui_scaled_resources.grdp b/components/resources/flags_ui_scaled_resources.grdp new file mode 100644 index 0000000..84cc1dc --- /dev/null +++ b/components/resources/flags_ui_scaled_resources.grdp
@@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit-part> + <structure type="chrome_scaled_image" name="IDR_FLAGS_FAVICON" file="flags_ui/favicon_flags.png" /> +</grit-part>
diff --git a/components/rlz/rlz_tracker_unittest.cc b/components/rlz/rlz_tracker_unittest.cc index eb33d89..ba505ee 100644 --- a/components/rlz/rlz_tracker_unittest.cc +++ b/components/rlz/rlz_tracker_unittest.cc
@@ -8,8 +8,8 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/sequenced_worker_pool_owner.h" #include "base/thread_task_runner_handle.h" -#include "base/threading/sequenced_worker_pool.h" #include "base/time/time.h" #include "components/rlz/rlz_tracker_delegate.h" #include "net/url_request/url_request_test_util.h" @@ -30,12 +30,10 @@ class TestRLZTrackerDelegate : public RLZTrackerDelegate { public: TestRLZTrackerDelegate() - : worker_pool_(new base::SequencedWorkerPool(1, "TestRLZTracker")), + : worker_pool_owner_(1, "TestRLZTracker"), request_context_getter_(new net::TestURLRequestContextGetter( base::ThreadTaskRunnerHandle::Get())) {} - ~TestRLZTrackerDelegate() override { worker_pool_->Shutdown(); } - void set_brand(const char* brand) { brand_override_ = brand; } void set_reactivation_brand(const char* reactivation_brand) { @@ -68,7 +66,7 @@ bool IsOnUIThread() override { return true; } base::SequencedWorkerPool* GetBlockingPool() override { - return worker_pool_.get(); + return worker_pool_owner_.pool().get(); } net::URLRequestContextGetter* GetRequestContext() override { @@ -108,7 +106,7 @@ } private: - scoped_refptr<base::SequencedWorkerPool> worker_pool_; + base::SequencedWorkerPoolOwner worker_pool_owner_; scoped_refptr<net::URLRequestContextGetter> request_context_getter_; std::string brand_override_;
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc b/components/scheduler/child/webthread_impl_for_worker_scheduler.cc index 8cd69b80..4c8335e 100644 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc +++ b/components/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -20,8 +20,13 @@ WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( const char* name) - : thread_(new base::Thread(name)) { - thread_->Start(); + : WebThreadImplForWorkerScheduler(name, base::Thread::Options()) {} + +WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( + const char* name, + base::Thread::Options options) + : thread_(new base::Thread(name ? name : std::string())) { + thread_->StartWithOptions(options); thread_task_runner_ = thread_->task_runner(); base::WaitableEvent completion(false, false);
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler.h b/components/scheduler/child/webthread_impl_for_worker_scheduler.h index 5075313..a198237 100644 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler.h +++ b/components/scheduler/child/webthread_impl_for_worker_scheduler.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ #define COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ +#include "base/threading/thread.h" #include "components/scheduler/base/task_queue_manager.h" #include "components/scheduler/child/webthread_base.h" @@ -28,6 +29,8 @@ public base::MessageLoop::DestructionObserver { public: explicit WebThreadImplForWorkerScheduler(const char* name); + WebThreadImplForWorkerScheduler(const char* name, + base::Thread::Options options); ~WebThreadImplForWorkerScheduler() override; // blink::WebThread implementation.
diff --git a/components/search_engines/search_terms_data.cc b/components/search_engines/search_terms_data.cc index e8abc03d3..be897db 100644 --- a/components/search_engines/search_terms_data.cc +++ b/components/search_engines/search_terms_data.cc
@@ -76,6 +76,10 @@ return std::string(); } +std::string SearchTermsData::IOSWebViewTypeParam() const { + return std::string(); +} + std::string SearchTermsData::GoogleImageSearchSource() const { return std::string(); }
diff --git a/components/search_engines/search_terms_data.h b/components/search_engines/search_terms_data.h index 2dcdd41..96c8854 100644 --- a/components/search_engines/search_terms_data.h +++ b/components/search_engines/search_terms_data.h
@@ -70,6 +70,11 @@ // non-empty for UIThreadSearchTermsData. virtual std::string NTPIsThemedParam() const; + // Returns a string indicating which webview is currently in use on iOS, + // suitable for adding as a query string param to search requests. Returns an + // empty string if no parameter should be passed along with search requests. + virtual std::string IOSWebViewTypeParam() const; + // Returns the value to use for replacements of type // GOOGLE_IMAGE_SEARCH_SOURCE. virtual std::string GoogleImageSearchSource() const;
diff --git a/components/security_interstitials.gypi b/components/security_interstitials.gypi index ba336af..583e5b02 100644 --- a/components/security_interstitials.gypi +++ b/components/security_interstitials.gypi
@@ -10,6 +10,7 @@ 'type': 'static_library', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:base_i18n', '../net/net.gyp:net', '../ui/base/ui_base.gyp:ui_base', 'components_strings.gyp:components_strings', @@ -17,12 +18,18 @@ 'history_core_browser', 'metrics', 'rappor', + 'ssl_errors', + 'url_formatter/url_formatter.gyp:url_formatter' ], 'include_dirs': [ '..', ], 'sources': [ # Note: sources list duplicated in GN build. + 'security_interstitials/core/bad_clock_ui.cc', + 'security_interstitials/core/bad_clock_ui.h', + 'security_interstitials/core/common_string_util.cc', + 'security_interstitials/core/common_string_util.h', 'security_interstitials/core/controller_client.cc', 'security_interstitials/core/controller_client.h', 'security_interstitials/core/metrics_helper.cc',
diff --git a/components/security_interstitials/DEPS b/components/security_interstitials/DEPS index 59d6ff0..e89fe67 100644 --- a/components/security_interstitials/DEPS +++ b/components/security_interstitials/DEPS
@@ -3,7 +3,10 @@ "+components/history/core/browser", "+components/metrics", "+components/rappor", + "+components/ssl_errors", + "+components/url_formatter", "+grit/components_strings.h", "+net/base", + "+net/ssl", "+ui/base" ]
diff --git a/components/security_interstitials/core/BUILD.gn b/components/security_interstitials/core/BUILD.gn index fc9f6a3..797bfd6e 100644 --- a/components/security_interstitials/core/BUILD.gn +++ b/components/security_interstitials/core/BUILD.gn
@@ -5,6 +5,10 @@ # GYP version: components/security_interstitials.gyp:security_interstitials_core static_library("core") { sources = [ + "bad_clock_ui.cc", + "bad_clock_ui.h", + "common_string_util.cc", + "common_string_util.h", "controller_client.cc", "controller_client.h", "metrics_helper.cc", @@ -13,12 +17,15 @@ deps = [ "//base", + "//base:i18n", "//base:prefs", "//components/google/core/browser", "//components/history/core/browser", "//components/metrics", "//components/rappor", + "//components/ssl_errors", "//components/strings", + "//components/url_formatter", "//net", "//ui/base", ]
diff --git a/components/security_interstitials/core/bad_clock_ui.cc b/components/security_interstitials/core/bad_clock_ui.cc new file mode 100644 index 0000000..7b39de7 --- /dev/null +++ b/components/security_interstitials/core/bad_clock_ui.cc
@@ -0,0 +1,119 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/security_interstitials/core/bad_clock_ui.h" + +#include "base/i18n/time_formatting.h" +#include "components/security_interstitials/core/common_string_util.h" +#include "components/security_interstitials/core/metrics_helper.h" +#include "grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace security_interstitials { + +BadClockUI::BadClockUI(const GURL& request_url, + int cert_error, + const net::SSLInfo& ssl_info, + const base::Time& time_triggered, + const std::string& languages, + ControllerClient* controller) + : request_url_(request_url), + cert_error_(cert_error), + ssl_info_(ssl_info), + time_triggered_(time_triggered), + languages_(languages), + controller_(controller) { + controller_->metrics_helper()->RecordUserInteraction( + security_interstitials::MetricsHelper::TOTAL_VISITS); + + // TODO(felt): Separate the clock statistics from the main ssl statistics. + ssl_errors::RecordUMAStatistics(false, time_triggered_, request_url_, + cert_error_, *ssl_info_.cert.get()); +} + +BadClockUI::~BadClockUI() { + controller_->metrics_helper()->RecordShutdownMetrics(); +} + +void BadClockUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) { + CHECK(load_time_data); + + // Shared with other SSL errors. + common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data); + common_string_util::PopulateSSLDebuggingStrings(ssl_info_, time_triggered_, + load_time_data); + + // Clock-specific strings. + PopulateClockStrings(load_time_data); + load_time_data->SetString("finalParagraph", std::string()); // Placeholder. +} + +void BadClockUI::PopulateClockStrings(base::DictionaryValue* load_time_data) { + load_time_data->SetBoolean("bad_clock", true); + load_time_data->SetBoolean("overridable", false); + load_time_data->SetBoolean("hide_primary_button", + !controller_->CanLaunchDateAndTimeSettings()); + int heading_string = ssl_errors::IsUserClockInTheFuture(time_triggered_) + ? IDS_CLOCK_ERROR_AHEAD_HEADING + : IDS_CLOCK_ERROR_BEHIND_HEADING; + load_time_data->SetString("tabTitle", + l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_TITLE)); + load_time_data->SetString("heading", + l10n_util::GetStringUTF16(heading_string)); + load_time_data->SetString( + "primaryParagraph", + l10n_util::GetStringFUTF16( + IDS_CLOCK_ERROR_PRIMARY_PARAGRAPH, + common_string_util::GetFormattedHostName(request_url_, languages_), + base::TimeFormatFriendlyDateAndTime(time_triggered_))); + load_time_data->SetString( + "primaryButtonText", + l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_UPDATE_DATE_AND_TIME)); + load_time_data->SetString( + "explanationParagraph", + l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_EXPLANATION)); +} + +void BadClockUI::HandleCommand(SecurityInterstitialCommands command) { + switch (command) { + case CMD_DONT_PROCEED: + controller_->GoBack(); + break; + case CMD_DO_REPORT: + controller_->SetReportingPreference(true); + break; + case CMD_DONT_REPORT: + controller_->SetReportingPreference(false); + break; + case CMD_SHOW_MORE_SECTION: + controller_->metrics_helper()->RecordUserInteraction( + security_interstitials::MetricsHelper::SHOW_ADVANCED); + break; + case CMD_OPEN_DATE_SETTINGS: + if (!controller_->CanLaunchDateAndTimeSettings()) + NOTREACHED() << "This platform does not support date settings"; + controller_->metrics_helper()->RecordUserInteraction( + security_interstitials::MetricsHelper::OPEN_TIME_SETTINGS); + controller_->LaunchDateAndTimeSettings(); + break; + case CMD_OPEN_REPORTING_PRIVACY: + controller_->OpenExtendedReportingPrivacyPolicy(); + break; + case CMD_PROCEED: + case CMD_OPEN_HELP_CENTER: + case CMD_RELOAD: + case CMD_OPEN_DIAGNOSTIC: + case CMD_OPEN_LOGIN: + case CMD_REPORT_PHISHING_ERROR: + // Not supported by the bad clock error page. + NOTREACHED() << "Unsupported command: " << command; + case CMD_ERROR: + case CMD_TEXT_FOUND: + case CMD_TEXT_NOT_FOUND: + // Commands are only for testing. + NOTREACHED() << "Unexpected command: " << command; + } +} + +} // security_interstitials
diff --git a/components/security_interstitials/core/bad_clock_ui.h b/components/security_interstitials/core/bad_clock_ui.h new file mode 100644 index 0000000..2ec5c63 --- /dev/null +++ b/components/security_interstitials/core/bad_clock_ui.h
@@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SECURITY_INTERSTITIALS_CORE_BAD_CLOCK_UI_H_ +#define COMPONENTS_SECURITY_INTERSTITIALS_CORE_BAD_CLOCK_UI_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "base/values.h" +#include "components/security_interstitials/core/controller_client.h" +#include "components/ssl_errors/error_classification.h" +#include "net/ssl/ssl_info.h" +#include "url/gurl.h" + +namespace security_interstitials { + +// Provides UI for SSL errors caused by clock misconfigurations. +class BadClockUI { + public: + BadClockUI(const GURL& request_url, + int cert_error, // Should correspond to a NET_ERROR + const net::SSLInfo& ssl_info, + const base::Time& time_triggered, // Time the error was triggered + const std::string& languages, + ControllerClient* controller_); + ~BadClockUI(); + + void PopulateStringsForHTML(base::DictionaryValue* load_time_data); + void HandleCommand(SecurityInterstitialCommands command); + + private: + void PopulateClockStrings(base::DictionaryValue* load_time_data); + + const GURL request_url_; + const int cert_error_; + const net::SSLInfo ssl_info_; + const base::Time time_triggered_; + const std::string languages_; + ControllerClient* controller_; + + DISALLOW_COPY_AND_ASSIGN(BadClockUI); +}; + +} // security_interstitials + +#endif // COMPONENTS_SECURITY_INTERSTITIALS_CORE_BAD_CLOCK_UI_H_
diff --git a/components/security_interstitials/core/common_string_util.cc b/components/security_interstitials/core/common_string_util.cc new file mode 100644 index 0000000..1f9bd44 --- /dev/null +++ b/components/security_interstitials/core/common_string_util.cc
@@ -0,0 +1,56 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/security_interstitials/core/common_string_util.h" + +#include "base/i18n/rtl.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/string_util.h" +#include "components/url_formatter/url_formatter.h" +#include "grit/components_strings.h" +#include "net/base/net_errors.h" +#include "ui/base/l10n/l10n_util.h" + +namespace security_interstitials { + +namespace common_string_util { + +base::string16 GetFormattedHostName(const GURL& gurl, + const std::string& languages) { + base::string16 host = url_formatter::IDNToUnicode(gurl.host(), languages); + if (base::i18n::IsRTL()) + base::i18n::WrapStringWithLTRFormatting(&host); + return host; +} + +void PopulateSSLLayoutStrings(int cert_error, + base::DictionaryValue* load_time_data) { + load_time_data->SetString("type", "SSL"); + load_time_data->SetString("errorCode", net::ErrorToString(cert_error)); + load_time_data->SetString( + "openDetails", l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON)); + load_time_data->SetString( + "closeDetails", l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON)); +} + +void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info, + const base::Time time_triggered, + base::DictionaryValue* load_time_data) { + load_time_data->SetString("subject", + ssl_info.cert->subject().GetDisplayName()); + load_time_data->SetString("issuer", ssl_info.cert->issuer().GetDisplayName()); + load_time_data->SetString( + "expirationDate", + base::TimeFormatShortDate(ssl_info.cert->valid_expiry())); + load_time_data->SetString("currentDate", + base::TimeFormatShortDate(time_triggered)); + std::vector<std::string> encoded_chain; + ssl_info.cert->GetPEMEncodedChain(&encoded_chain); + load_time_data->SetString( + "pem", base::JoinString(encoded_chain, base::StringPiece())); +} + +} // namespace common_string_util + +} // namespace security_interstitials
diff --git a/components/security_interstitials/core/common_string_util.h b/components/security_interstitials/core/common_string_util.h new file mode 100644 index 0000000..6f094f3 --- /dev/null +++ b/components/security_interstitials/core/common_string_util.h
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SECURITY_INTERSTITIALS_CORE_COMMON_STRING_UTIL_H_ +#define COMPONENTS_SECURITY_INTERSTITIALS_CORE_COMMON_STRING_UTIL_H_ + +#include "base/macros.h" +#include "base/time/time.h" +#include "base/values.h" +#include "net/ssl/ssl_info.h" +#include "url/gurl.h" + +namespace security_interstitials { + +// This namespace contains shared functionality for manipulating the strings +// and string resources in security error pages. +namespace common_string_util { + +// Returns the |gurl| as a URL appropriate for display in an error page. +base::string16 GetFormattedHostName(const GURL& gurl, + const std::string& languages); + +// For SSL-related errors that share a basic structure. +void PopulateSSLLayoutStrings(int cert_error, + base::DictionaryValue* load_time_data); + +// For SSL-related errors that provide debugging information. +void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info, + const base::Time time_triggered, + base::DictionaryValue* load_time_data); + +} // common_string_util + +} // namespace security_interstitials + +#endif // COMPONENTS_SECURITY_INTERSTITIALS_CORE_COMMON_STRING_UTIL_H_
diff --git a/components/security_interstitials/core/controller_client.h b/components/security_interstitials/core/controller_client.h index 6eb41e0..6f0b47b 100644 --- a/components/security_interstitials/core/controller_client.h +++ b/components/security_interstitials/core/controller_client.h
@@ -51,7 +51,8 @@ }; // Provides methods for handling commands from the user, which requires some -// embedder-specific abstraction. +// embedder-specific abstraction. This class should handle all commands sent +// by the JavaScript error page. class ControllerClient { public: ControllerClient(); @@ -61,6 +62,13 @@ void SetReportingPreference(bool report); void OpenExtendedReportingPrivacyPolicy(); + // If available, open the operating system's date/time settings. + virtual bool CanLaunchDateAndTimeSettings() = 0; + virtual void LaunchDateAndTimeSettings() = 0; + + // Close the error and go back to the previous page. + virtual void GoBack() = 0; + MetricsHelper* metrics_helper() const; void set_metrics_helper(scoped_ptr<MetricsHelper> metrics_helper);
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc index 15bd8bb..a5cb5fb 100644 --- a/components/test_runner/event_sender.cc +++ b/components/test_runner/event_sender.cc
@@ -93,6 +93,7 @@ e->y = pos.y; e->globalX = pos.x; e->globalY = pos.y; + e->pointerType = blink::WebPointerProperties::PointerType::Mouse; e->timeStampSeconds = time_stamp; e->clickCount = click_count; }
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc index c5bccb0..d8ad6df 100644 --- a/components/update_client/update_client_unittest.cc +++ b/components/update_client/update_client_unittest.cc
@@ -137,7 +137,6 @@ protected: void RunThreads(); - void StopWorkerPool(); // Returns the full path to a test file. static base::FilePath TestFilePath(const char* file); @@ -178,10 +177,6 @@ runloop_.Run(); } -void UpdateClientTest::StopWorkerPool() { - worker_pool_->pool()->Shutdown(); -} - base::FilePath UpdateClientTest::TestFilePath(const char* file) { base::FilePath path; PathService::Get(base::DIR_SOURCE_ROOT, &path); @@ -287,8 +282,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the scenario where two CRXs are checked for updates. On CRX has @@ -470,8 +463,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the update check for two CRXs scenario. Both CRXs have updates. @@ -708,8 +699,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the scenario where there is a download timeout for the first @@ -946,8 +935,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the differential update scenario for one CRX. @@ -1212,8 +1199,6 @@ } update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the update scenario for one CRX where the CRX installer returns @@ -1406,8 +1391,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the fallback from differential to full update scenario for one CRX. @@ -1691,8 +1674,6 @@ } update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the queuing of update checks. In this scenario, two update checks are @@ -1797,8 +1778,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests the install of one CRX. @@ -1970,8 +1949,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Tests that overlapping installs of the same CRX result in an error. @@ -2084,8 +2061,6 @@ RunThreads(); update_client->RemoveObserver(&observer); - - StopWorkerPool(); } // Make sure that we don't get any crashes when trying to update an empty list @@ -2144,8 +2119,6 @@ empty_id_list, base::Bind(&DataCallbackFake::Callback), base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); runloop.Run(); - - StopWorkerPool(); } } // namespace update_client
diff --git a/components/version_info/version_info.cc b/components/version_info/version_info.cc index a6c3916..7065778 100644 --- a/components/version_info/version_info.cc +++ b/components/version_info/version_info.cc
@@ -9,7 +9,7 @@ #include "grit/components_strings.h" #if defined(USE_UNOFFICIAL_VERSION_NUMBER) -#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/l10n_util.h" // nogncheck #endif // USE_UNOFFICIAL_VERSION_NUMBER namespace version_info {
diff --git a/components/wifi_sync/BUILD.gn b/components/wifi_sync/BUILD.gn index 03444289..72ac120 100644 --- a/components/wifi_sync/BUILD.gn +++ b/components/wifi_sync/BUILD.gn
@@ -22,21 +22,22 @@ deps = [ "//base", + "//base:i18n", + "//components/keyed_service/content", + "//components/keyed_service/core", "//components/onc", + "//content/public/browser", "//sync", ] + + if (is_chromeos) { + deps += [ "//chromeos" ] + } } source_set("unit_tests") { testonly = true - deps = [ - ":wifi_sync", - "//sync", - "//testing/gmock", - "//testing/gtest", - ] - sources = [ "wifi_config_delegate_chromeos_unittest.cc", "wifi_credential_syncable_service_unittest.cc", @@ -44,4 +45,14 @@ "wifi_security_class_chromeos_unittest.cc", "wifi_security_class_unittest.cc", ] + + deps = [ + ":wifi_sync", + "//base", + "//chromeos", + "//components/onc", + "//sync:test_support_sync_api", + "//testing/gmock", + "//testing/gtest", + ] }
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc index 04cf9e94..acda33e 100644 --- a/content/browser/android/content_startup_flags.cc +++ b/content/browser/android/content_startup_flags.cc
@@ -82,9 +82,9 @@ #if !defined(USE_AURA) cc::LayerSettings layer_settings; - if (parsed_command_line->HasSwitch( - switches::kEnableAndroidCompositorAnimationTimelines)) - layer_settings.use_compositor_animation_timelines = true; + layer_settings.use_compositor_animation_timelines = + !parsed_command_line->HasSwitch( + switches::kDisableAndroidCompositorAnimationTimelines); Compositor::SetLayerSettings(layer_settings); #endif }
diff --git a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc index b747752..f65a96ae 100644 --- a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc +++ b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
@@ -7,6 +7,8 @@ #include <stdint.h> #include <unistd.h> +#include <limits> + #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/strings/string_number_conversions.h" @@ -34,19 +36,19 @@ // Rounds to jlong using Java's type conversion rules. jlong RoundDoubleToLong(const double& x) { double intermediate = RoundDoubleTowardsZero(x); - // The int64 limits can not be converted exactly to double values, so we + // The int64_t limits can not be converted exactly to double values, so we // compare to custom constants. kint64max is 2^63 - 1, but the spacing // between double values in the the range 2^62 to 2^63 is 2^10. The cast is // required to silence a spurious gcc warning for integer overflow. - const int64 kLimit = (INT64_C(1) << 63) - static_cast<uint64>(1 << 10); + const int64_t kLimit = (INT64_C(1) << 63) - static_cast<uint64_t>(1 << 10); DCHECK(kLimit > 0); const double kLargestDoubleLessThanInt64Max = kLimit; const double kSmallestDoubleGreaterThanInt64Min = -kLimit; if (intermediate > kLargestDoubleLessThanInt64Max) { - return kint64max; + return std::numeric_limits<int64_t>::max(); } if (intermediate < kSmallestDoubleGreaterThanInt64Min) { - return kint64min; + return std::numeric_limits<int64_t>::min(); } return static_cast<jlong>(intermediate); } @@ -54,9 +56,11 @@ // Rounds to jint using Java's type conversion rules. jint RoundDoubleToInt(const double& x) { double intermediate = RoundDoubleTowardsZero(x); - // The int32 limits cast exactly to double values. - intermediate = std::min(intermediate, static_cast<double>(kint32max)); - intermediate = std::max(intermediate, static_cast<double>(kint32min)); + // The int32_t limits cast exactly to double values. + intermediate = std::min( + intermediate, static_cast<double>(std::numeric_limits<int32_t>::max())); + intermediate = std::max( + intermediate, static_cast<double>(std::numeric_limits<int32_t>::min())); return static_cast<jint>(intermediate); } @@ -514,13 +518,14 @@ if (length_value->IsType(base::Value::TYPE_INTEGER)) { int int_length; length_value->GetAsInteger(&int_length); - if (int_length >= 0 && int_length <= kint32max) { + if (int_length >= 0 && int_length <= std::numeric_limits<int32_t>::max()) { length = static_cast<jsize>(int_length); } } else if (length_value->IsType(base::Value::TYPE_DOUBLE)) { double double_length; length_value->GetAsDouble(&double_length); - if (double_length >= 0.0 && double_length <= kint32max) { + if (double_length >= 0.0 && + double_length <= std::numeric_limits<int32_t>::max()) { length = static_cast<jsize>(double_length); } }
diff --git a/content/browser/blob_storage/blob_async_builder_host_unittest.cc b/content/browser/blob_storage/blob_async_builder_host_unittest.cc new file mode 100644 index 0000000..ddf29315 --- /dev/null +++ b/content/browser/blob_storage/blob_async_builder_host_unittest.cc
@@ -0,0 +1,323 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/blob/blob_async_builder_host.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "storage/common/blob_storage/blob_storage_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace storage { +namespace { +const std::string kBlobUUID = "blobUUIDYAY"; +const std::string kFakeBlobUUID = "fakeBlob"; +const std::string kBlobType = "blobtypeYAY"; + +const size_t kTestBlobStorageIPCThresholdBytes = 5; +const size_t kTestBlobStorageMaxSharedMemoryBytes = 20; +const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; + +void PopulateBytes(char* bytes, size_t length) { + for (size_t i = 0; i < length; i++) { + bytes[i] = static_cast<char>(i); + } +} + +void AddMemoryItem(size_t length, std::vector<DataElement>* out) { + DataElement bytes; + bytes.SetToBytesDescription(length); + out->push_back(bytes); +} + +void AddShortcutMemoryItem(size_t length, std::vector<DataElement>* out) { + DataElement bytes; + bytes.SetToAllocatedBytes(length); + PopulateBytes(bytes.mutable_bytes(), length); + out->push_back(bytes); +} + +void AddShortcutMemoryItem(size_t length, BlobDataBuilder* out) { + DataElement bytes; + bytes.SetToAllocatedBytes(length); + PopulateBytes(bytes.mutable_bytes(), length); + out->AppendData(bytes.bytes(), length); +} + +void AddBlobItem(std::vector<DataElement>* out) { + DataElement blob; + blob.SetToBlob(kFakeBlobUUID); + out->push_back(blob); +} + +class BlobAsyncBuilderHostTest : public testing::Test { + protected: + BlobAsyncBuilderHostTest() + : matching_builder_(nullptr), + done_called_(false), + cancel_called_(false), + cancel_code_(IPCBlobCreationCancelCode::UNKNOWN), + request_called_(false) {} + ~BlobAsyncBuilderHostTest() override {} + + void SetUp() override { + matching_builder_ = nullptr; + done_called_ = false; + cancel_called_ = false; + cancel_code_ = IPCBlobCreationCancelCode::UNKNOWN; + request_called_ = false; + requests_.clear(); + memory_handles_.clear(); + file_handles_.clear(); + host_.SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes, + kTestBlobStorageMaxSharedMemoryBytes, + kTestBlobStorageMaxFileSizeBytes); + } + + void SetMatchingBuilder(BlobDataBuilder* builder) { + matching_builder_ = builder; + } + + void CancelCallback(IPCBlobCreationCancelCode code) { + cancel_called_ = true; + cancel_code_ = code; + } + + void DoneCallback(const BlobDataBuilder& builder) { + // This does a deep comparison, including internal data items. + if (matching_builder_) + EXPECT_EQ(*matching_builder_, builder); + done_called_ = true; + } + + void RequestMemoryCallback( + const std::vector<storage::BlobItemBytesRequest>& requests, + const std::vector<base::SharedMemoryHandle>& shared_memory_handles, + const std::vector<uint64_t>& file_sizes) { + this->requests_ = requests; + memory_handles_ = shared_memory_handles; + file_handles_ = file_sizes; + request_called_ = true; + } + + bool BuildBlobAsync(const std::vector<DataElement>& descriptions, + size_t memory_available) { + done_called_ = false; + cancel_called_ = false; + request_called_ = false; + return host_.StartBuildingBlob( + kBlobUUID, kBlobType, descriptions, memory_available, + base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback, + base::Unretained(this)), + base::Bind(&BlobAsyncBuilderHostTest::DoneCallback, + base::Unretained(this)), + base::Bind(&BlobAsyncBuilderHostTest::CancelCallback, + base::Unretained(this))); + } + + BlobDataBuilder* matching_builder_; + BlobAsyncBuilderHost host_; + bool done_called_; + bool cancel_called_; + IPCBlobCreationCancelCode cancel_code_; + + bool request_called_; + std::vector<storage::BlobItemBytesRequest> requests_; + std::vector<base::SharedMemoryHandle> memory_handles_; + std::vector<uint64_t> file_handles_; +}; + +TEST_F(BlobAsyncBuilderHostTest, TestShortcut) { + std::vector<DataElement> descriptions; + + AddShortcutMemoryItem(10, &descriptions); + AddBlobItem(&descriptions); + AddShortcutMemoryItem(5000, &descriptions); + + BlobDataBuilder expected(kBlobUUID); + expected.set_content_type(kBlobType); + AddShortcutMemoryItem(10, &expected); + expected.AppendBlob(kFakeBlobUUID); + AddShortcutMemoryItem(5000, &expected); + SetMatchingBuilder(&expected); + + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + + EXPECT_TRUE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_FALSE(request_called_); + EXPECT_EQ(0u, host_.blob_building_count()); +}; + +TEST_F(BlobAsyncBuilderHostTest, TestSingleSharedMemRequest) { + std::vector<DataElement> descriptions; + const size_t kSize = kTestBlobStorageIPCThresholdBytes + 1; + AddMemoryItem(kSize, &descriptions); + + EXPECT_TRUE( + BuildBlobAsync(descriptions, kTestBlobStorageIPCThresholdBytes + 1)); + + EXPECT_FALSE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_TRUE(request_called_); + EXPECT_EQ(1u, host_.blob_building_count()); + ASSERT_EQ(1u, requests_.size()); + request_called_ = false; + + EXPECT_EQ( + BlobItemBytesRequest::CreateSharedMemoryRequest(0, 0, 0, kSize, 0, 0), + requests_.at(0)); +}; + +TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) { + std::vector<DataElement> descriptions; + const size_t kSize = kTestBlobStorageMaxSharedMemoryBytes + 1; + const char kFirstBlockByte = 7; + const char kSecondBlockByte = 19; + AddMemoryItem(kSize, &descriptions); + + BlobDataBuilder expected(kBlobUUID); + expected.set_content_type(kBlobType); + char data[kSize]; + memset(data, kFirstBlockByte, kTestBlobStorageMaxSharedMemoryBytes); + expected.AppendData(data, kTestBlobStorageMaxSharedMemoryBytes); + expected.AppendData(&kSecondBlockByte, 1); + SetMatchingBuilder(&expected); + + EXPECT_TRUE( + BuildBlobAsync(descriptions, kTestBlobStorageMaxSharedMemoryBytes + 1)); + + EXPECT_FALSE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_TRUE(request_called_); + EXPECT_EQ(1u, host_.blob_building_count()); + ASSERT_EQ(1u, requests_.size()); + request_called_ = false; + + // We need to grab a duplicate handle so we can have two blocks open at the + // same time. + base::SharedMemoryHandle handle = + base::SharedMemory::DuplicateHandle(memory_handles_.at(0)); + EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); + base::SharedMemory shared_memory(handle, false); + EXPECT_TRUE(shared_memory.Map(kTestBlobStorageMaxSharedMemoryBytes)); + + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest( + 0, 0, 0, kTestBlobStorageMaxSharedMemoryBytes, 0, 0), + requests_.at(0)); + + memset(shared_memory.memory(), kFirstBlockByte, + kTestBlobStorageMaxSharedMemoryBytes); + + BlobItemBytesResponse response(0); + std::vector<BlobItemBytesResponse> responses = {response}; + EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); + + EXPECT_FALSE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_TRUE(request_called_); + EXPECT_EQ(1u, host_.blob_building_count()); + ASSERT_EQ(1u, requests_.size()); + request_called_ = false; + + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest( + 1, 0, kTestBlobStorageMaxSharedMemoryBytes, 1, 0, 0), + requests_.at(0)); + + memset(shared_memory.memory(), kSecondBlockByte, 1); + + response.request_number = 1; + responses[0] = response; + EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); + EXPECT_TRUE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_FALSE(request_called_); + EXPECT_EQ(0u, host_.blob_building_count()); +}; + +TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) { + std::vector<DataElement> descriptions; + + AddMemoryItem(2, &descriptions); + AddBlobItem(&descriptions); + AddMemoryItem(2, &descriptions); + + BlobDataBuilder expected(kBlobUUID); + expected.set_content_type(kBlobType); + AddShortcutMemoryItem(2, &expected); + expected.AppendBlob(kFakeBlobUUID); + AddShortcutMemoryItem(2, &expected); + SetMatchingBuilder(&expected); + + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + host_.StopBuildingBlob(kBlobUUID); + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + + EXPECT_FALSE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_TRUE(request_called_); + EXPECT_EQ(1u, host_.blob_building_count()); + request_called_ = false; + + BlobItemBytesResponse response1(0); + PopulateBytes(response1.allocate_mutable_data(2), 2); + BlobItemBytesResponse response2(1); + PopulateBytes(response2.allocate_mutable_data(2), 2); + std::vector<BlobItemBytesResponse> responses = {response1, response2}; + EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); + EXPECT_TRUE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_FALSE(request_called_); + EXPECT_EQ(0u, host_.blob_building_count()); +}; + +TEST_F(BlobAsyncBuilderHostTest, TestBadIPCs) { + std::vector<DataElement> descriptions; + + // Test reusing same blob uuid. + SetMatchingBuilder(nullptr); + AddMemoryItem(10, &descriptions); + AddBlobItem(&descriptions); + AddMemoryItem(5000, &descriptions); + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + EXPECT_FALSE(BuildBlobAsync(descriptions, 5010)); + EXPECT_FALSE(done_called_); + EXPECT_FALSE(cancel_called_); + EXPECT_FALSE(request_called_); + host_.StopBuildingBlob(kBlobUUID); + + // Test we're _not_ an error if we get a bad uuid for responses. + BlobItemBytesResponse response(0); + std::vector<BlobItemBytesResponse> responses = {response}; + EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses)); + + // Test empty responses. + responses.clear(); + EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); + + // Test response problems below here. + descriptions.clear(); + AddMemoryItem(2, &descriptions); + AddBlobItem(&descriptions); + AddMemoryItem(2, &descriptions); + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + + // Invalid request number. + BlobItemBytesResponse response1(3); + PopulateBytes(response1.allocate_mutable_data(2), 2); + responses = {response1}; + EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); + + // Duplicate request number responses. + EXPECT_TRUE(BuildBlobAsync(descriptions, 5010)); + response1.request_number = 0; + BlobItemBytesResponse response2(0); + PopulateBytes(response2.allocate_mutable_data(2), 2); + responses = {response1, response2}; + EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses)); +}; + +} // namespace +} // namespace storage
diff --git a/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc b/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc new file mode 100644 index 0000000..dd45f2b --- /dev/null +++ b/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc
@@ -0,0 +1,455 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/blob/blob_async_transport_strategy.h" + +#include <string> + +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace storage { +namespace { + +const char kNewUUID[] = "newUUID"; +const base::FilePath kFuturePopulatingFilePath = base::FilePath::FromUTF8Unsafe( + std::string(BlobDataBuilder::kAppendFutureFileTemporaryFileName)); +const char kFakeBlobUUID[] = "fakeBlob"; + +void AddMemoryItem(size_t length, std::vector<DataElement>* out) { + DataElement bytes; + bytes.SetToBytesDescription(length); + out->push_back(bytes); +} + +void AddShortcutMemoryItem(size_t length, std::vector<DataElement>* out) { + DataElement bytes; + bytes.SetToAllocatedBytes(length); + for (size_t i = 0; i < length; i++) { + bytes.mutable_bytes()[i] = static_cast<char>(i); + } + out->push_back(bytes); +} + +void AddBlobItem(std::vector<DataElement>* out) { + DataElement blob; + blob.SetToBlob(kFakeBlobUUID); + out->push_back(blob); +} + +TEST(BlobAsyncTransportStrategyTest, TestNoMemoryItems) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // Here we test that we don't do any requests when there are no memory items. + AddBlobItem(&infos); + AddBlobItem(&infos); + AddBlobItem(&infos); + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_available + kNewUUID, infos); + + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(0u, strategy.handle_sizes().size()); + EXPECT_EQ(0u, strategy.requests().size()); + + BlobDataBuilder builder(kNewUUID); + builder.AppendBlob(kFakeBlobUUID); + builder.AppendBlob(kFakeBlobUUID); + builder.AppendBlob(kFakeBlobUUID); + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, TestLargeBlockToFile) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // Here we test our size > max_blob_in_memory_size (100), + // and we save to one file. (size < max_file_size) + AddMemoryItem(305, &infos); + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_available + kNewUUID, infos); + + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(1u, strategy.handle_sizes().size()); + EXPECT_EQ(305ul, strategy.handle_sizes().at(0)); + EXPECT_EQ(1u, strategy.requests().size()); + + auto& memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 305ull, 0u, 0ull), + memory_item_request.message); + + BlobDataBuilder builder(kNewUUID); + builder.AppendFile(kFuturePopulatingFilePath, 0, 305, + base::Time::FromDoubleT(0)); + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, TestLargeBlockToFiles) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // Here we test our size > max_blob_in_memory_size (300), + // and we save 3 files. (size > max_file_size) + AddMemoryItem(1000, &infos); + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_available + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(3u, strategy.handle_sizes().size()); + EXPECT_EQ(400ul, strategy.handle_sizes().at(0)); + EXPECT_EQ(400ul, strategy.handle_sizes().at(1)); + EXPECT_EQ(200ul, strategy.handle_sizes().at(2)); + EXPECT_EQ(3u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 400ull, 0u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(1); + EXPECT_EQ(1u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(1u, 0u, 400ull, 400ull, 1u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(2); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(2u, 0u, 800ull, 200ull, 2u, 0ull), + memory_item_request.message); + + BlobDataBuilder builder(kNewUUID); + builder.AppendFile(kFuturePopulatingFilePath, 0, 400, + base::Time::FromDoubleT(0)); + builder.AppendFile(kFuturePopulatingFilePath, 0, 400, + base::Time::FromDoubleT(0)); + builder.AppendFile(kFuturePopulatingFilePath, 0, 200, + base::Time::FromDoubleT(0)); + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, TestLargeBlocksConsolidatingInFiles) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // We should have 3 storage items for the memory, two files, 400 each. + // We end up with storage items: + // 1: File A, 300MB + // 2: Blob + // 3: File A, 100MB (300MB offset) + // 4: File B, 400MB + AddMemoryItem(300, &infos); + AddBlobItem(&infos); + AddMemoryItem(500, &infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_available + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(2u, strategy.handle_sizes().size()); + EXPECT_EQ(400ul, strategy.handle_sizes().at(0)); + EXPECT_EQ(400ul, strategy.handle_sizes().at(1)); + EXPECT_EQ(3u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 300ull, 0u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(1); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(1u, 2u, 0ull, 100ull, 0u, 300ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(2); + EXPECT_EQ(3u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ( + BlobItemBytesRequest::CreateFileRequest(2u, 2u, 100ull, 400ull, 1u, 0ull), + memory_item_request.message); +} + +TEST(BlobAsyncTransportStrategyTest, TestSharedMemorySegmentation) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // For transport we should have 3 shared memories, and then storage in 3 + // browser items. + // (size > max_shared_memory_size and size < max_blob_in_memory_size + AddMemoryItem(500, &infos); + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 300, // max_file_size + 5000, // disk_space_left + 500, // memory_available + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(3u, strategy.handle_sizes().size()); + EXPECT_EQ(200u, strategy.handle_sizes().at(0)); + EXPECT_EQ(200u, strategy.handle_sizes().at(1)); + EXPECT_EQ(100u, strategy.handle_sizes().at(2)); + EXPECT_EQ(3u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull, + 200ull, 0u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(1); + EXPECT_EQ(1u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 0u, 200ull, + 200ull, 1u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(2); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 0u, 400ull, + 100ull, 2u, 0ull), + memory_item_request.message); + + BlobDataBuilder builder(kNewUUID); + builder.AppendFutureData(200); + builder.AppendFutureData(200); + builder.AppendFutureData(100); + + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, TestSharedMemorySegmentationAndStorage) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // For transport, we should have 2 shared memories, where the first one + // have half 0 and half 3, and then the last one has half 3. + // + // For storage, we should have 3 browser items that match the pre-transport + // version: + // 1: Bytes 100MB + // 2: Blob + // 3: Bytes 200MB + AddShortcutMemoryItem(100, &infos); // should have no behavior change + AddBlobItem(&infos); + AddMemoryItem(200, &infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 300, // max_file_size + 5000, // disk_space_left + 300, // memory_available + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + EXPECT_EQ(2u, strategy.handle_sizes().size()); + EXPECT_EQ(200u, strategy.handle_sizes().at(0)); + EXPECT_EQ(100u, strategy.handle_sizes().at(1)); + EXPECT_EQ(3u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull, + 100ull, 0u, 0ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(1); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 2u, 0ull, + 100ull, 0u, 100ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(2); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(100u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 2u, 100ull, + 100ull, 1u, 0ull), + memory_item_request.message); + + BlobDataBuilder builder(kNewUUID); + builder.AppendFutureData(100); + builder.AppendBlob(kFakeBlobUUID); + builder.AppendFutureData(200); + + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, TestTooLarge) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // Our item is too large for disk, so error out. + AddMemoryItem(5001, &infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_left + kNewUUID, infos); + + EXPECT_EQ(0u, strategy.handle_sizes().size()); + EXPECT_EQ(0u, strategy.handle_sizes().size()); + EXPECT_EQ(0u, strategy.requests().size()); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_TOO_LARGE, strategy.error()); +} + +TEST(BlobAsyncTransportStrategyTest, TestNoDisk) { + BlobAsyncTransportStrategy strategy; + std::vector<DataElement> infos; + + // Our item is too large for memory, and we are in no_disk mode (incognito) + AddMemoryItem(301, &infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 0, // disk_space_left + 300, // memory_available + kNewUUID, infos); + + EXPECT_EQ(0u, strategy.handle_sizes().size()); + EXPECT_EQ(0u, strategy.handle_sizes().size()); + EXPECT_EQ(0u, strategy.requests().size()); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_TOO_LARGE, strategy.error()); +} + +TEST(BlobAsyncTransportStrategyTest, TestSimpleIPC) { + // Test simple IPC strategy, where size < max_ipc_memory_size and we have + // just one item. + std::vector<DataElement> infos; + BlobAsyncTransportStrategy strategy; + AddMemoryItem(10, &infos); + AddBlobItem(&infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_left + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + ASSERT_EQ(1u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull), + memory_item_request.message); +} + +TEST(BlobAsyncTransportStrategyTest, TestMultipleIPC) { + // Same as above, but with 2 items and a blob in-between. + std::vector<DataElement> infos; + BlobAsyncTransportStrategy strategy; + infos.clear(); + AddShortcutMemoryItem(10, &infos); // should have no behavior change + AddBlobItem(&infos); + AddMemoryItem(80, &infos); + + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_left + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error()); + + ASSERT_EQ(2u, strategy.requests().size()); + + auto memory_item_request = strategy.requests().at(0); + EXPECT_EQ(0u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull), + memory_item_request.message); + + memory_item_request = strategy.requests().at(1); + EXPECT_EQ(2u, memory_item_request.browser_item_index); + EXPECT_EQ(0u, memory_item_request.browser_item_offset); + EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(1u, 2u, 0ull, 80ull), + memory_item_request.message); + + // We still populate future data, as the strategy assumes we will be + // requesting the data. + BlobDataBuilder builder(kNewUUID); + builder.AppendFutureData(10); + builder.AppendBlob(kFakeBlobUUID); + builder.AppendFutureData(80); + + EXPECT_EQ(builder, *strategy.blob_builder()); +} + +TEST(BlobAsyncTransportStrategyTest, Shortcut) { + std::vector<DataElement> infos; + AddMemoryItem(100, &infos); + AddBlobItem(&infos); + EXPECT_FALSE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 200)); + + infos.clear(); + AddShortcutMemoryItem(100, &infos); + AddBlobItem(&infos); + EXPECT_TRUE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 200)); + + infos.clear(); + AddShortcutMemoryItem(100, &infos); + EXPECT_FALSE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 99)); +} +} // namespace + +TEST(BlobAsyncTransportStrategyTest, TestInvalidParams) { + std::vector<DataElement> infos; + // In order to test uin64_t overflow, we would need to have an array with more + // than size_t entries (for 32 byte stuff). So this would only happen if the + // IPC was malformed. We instead have to friend this test from DataElement so + // we can modify the length to be > size_t. + + // Test uint64_t overflow. + BlobAsyncTransportStrategy strategy; + AddMemoryItem(1, &infos); + AddMemoryItem(1, &infos); + infos.back().length_ = std::numeric_limits<uint64_t>::max(); + strategy.Initialize(100, // max_ipc_memory_size + 200, // max_shared_memory_size + 400, // max_file_size + 5000, // disk_space_left + 100, // memory_left + kNewUUID, infos); + EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS, + strategy.error()); +} +} // namespace storage
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 61ee4a1..83e80aa 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -772,8 +772,8 @@ EXPECT_TRUE(CachePut(callback_cache_, stored_url_)); base::FilePath new_path = callback_cache_->path(); - // Close the cache. - callback_cache_ = nullptr; + // Close the cache's backend so that the files can be moved. + callback_cache_->Close(base::Bind(&base::DoNothing)); base::RunLoop().RunUntilIdle(); // Legacy index files didn't have the cache directory, so remove it from the
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 6b71c84..c705b7db 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -4,6 +4,8 @@ #include "content/browser/child_process_launcher.h" +#include <utility> + #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_util.h" @@ -139,7 +141,7 @@ #if defined(OS_ANDROID) files_to_register->Share(kPrimaryIPCChannel, ipcfd.get()); #else - files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass()); + files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd)); #endif #endif @@ -188,7 +190,7 @@ CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); StartChildProcess( - cmd_line->argv(), child_process_id, files_to_register.Pass(), regions, + cmd_line->argv(), child_process_id, std::move(files_to_register), regions, base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, begin_launch_time, base::Passed(&ipcfd))); @@ -199,7 +201,7 @@ #if !defined(OS_MACOSX) if (use_zygote) { base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest( - cmd_line->argv(), files_to_register.Pass(), process_type); + cmd_line->argv(), std::move(files_to_register), process_type); process = base::Process(handle); } else // Fall through to the normal posix case below when we're not zygoting. @@ -305,7 +307,7 @@ ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle()); } else #endif // !OS_MACOSX - base::EnsureProcessTerminated(process.Pass()); + base::EnsureProcessTerminated(std::move(process)); #endif // OS_POSIX #endif // defined(OS_ANDROID) } @@ -447,9 +449,9 @@ if (instance.get()) { instance->Notify(zygote, #if defined(OS_ANDROID) - ipcfd.Pass(), + std::move(ipcfd), #endif - process.Pass()); + std::move(process)); } else { if (process.IsValid() && terminate_on_shutdown) { // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So @@ -469,7 +471,7 @@ base::Process process) { DCHECK(CalledOnValidThread()); starting_ = false; - process_ = process.Pass(); + process_ = std::move(process); #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) zygote_ = zygote;
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index 9bad4d3..37b9b858 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc
@@ -1181,57 +1181,6 @@ recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); } -// Confirm restart fallback happens if a precondition is failed. -IN_PROC_BROWSER_TEST_F(DownloadContentTest, - ResumeInterruptedDownloadBadPrecondition) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableDownloadResumption); - ASSERT_TRUE(spawned_test_server()->Start()); - - GURL url = spawned_test_server()->GetURL(base::StringPrintf( - // First download hits an RST, rest don't, precondition fail. - "rangereset?size=%d&rst_boundary=%d&" - "token=BadPrecondition&rst_limit=1&fail_precondition=2", - GetSafeBufferChunk() * 3, GetSafeBufferChunk())); - - // Start the download and wait for first data chunk. - DownloadItem* download(StartDownloadAndReturnItem(url)); - WaitForData(download, GetSafeBufferChunk()); - - RecordingDownloadObserver recorder(download); - - ReleaseRSTAndConfirmInterruptForResume(download); - ConfirmFileStatusForResume( - download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, - base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); - EXPECT_EQ("BadPrecondition2", download->GetETag()); - - DownloadUpdatedObserver completion_observer( - download, base::Bind(DownloadCompleteFilter)); - download->Resume(); - completion_observer.WaitForEvent(); - - ConfirmFileStatusForResume( - download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, - base::FilePath(FILE_PATH_LITERAL("rangereset"))); - EXPECT_EQ("BadPrecondition0", download->GetETag()); - - static const RecordingDownloadObserver::RecordStruct expected_record[] = { - // Result of RST - {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, - // Starting continuation - {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, - // Server precondition fail. - {DownloadItem::INTERRUPTED, 0}, - // Notification of successful restart. - {DownloadItem::IN_PROGRESS, 0}, - // Completion. - {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, - }; - - recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); -} - // Confirm we don't try to resume if we don't have a verifier. IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoVerifiers) {
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc index 42c0f778..28340133 100644 --- a/content/browser/download/download_item_impl.cc +++ b/content/browser/download/download_item_impl.cc
@@ -891,7 +891,6 @@ mode = RESUME_MODE_IMMEDIATE_CONTINUE; break; - case DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION: case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE: case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT: if (force_user)
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 6a98bc2..95ce596 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -88,20 +88,21 @@ // We shouldn't be asked to continue if we don't have a verifier. DCHECK(params->offset() == 0 || has_etag || has_last_modified); - if (params->offset() > 0) { + if (params->offset() > 0 && (has_etag || has_last_modified)) { request->SetExtraRequestHeaderByName( "Range", base::StringPrintf("bytes=%" PRId64 "-", params->offset()), true); - if (has_last_modified) { - request->SetExtraRequestHeaderByName("If-Unmodified-Since", - params->last_modified(), - true); - } - if (has_etag) { - request->SetExtraRequestHeaderByName("If-Match", params->etag(), true); - } + // In accordance with RFC 2616 Section 14.27, use If-Range to specify that + // the server return the entire entity if the validator doesn't match. + // Last-Modified can be used in the absence of ETag as a validator if the + // response headers satisfied the HttpUtil::HasStrongValidators() predicate. + // + // This function assumes that HasStrongValidators() was true and that the + // ETag and Last-Modified header values supplied are valid. + request->SetExtraRequestHeaderByName( + "If-Range", has_etag ? params->etag() : params->last_modified(), true); } for (DownloadUrlParameters::RequestHeadersType::const_iterator iter
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc index 2b6ac35..5cc4ee81 100644 --- a/content/browser/download/download_resource_handler.cc +++ b/content/browser/download/download_resource_handler.cc
@@ -408,11 +408,6 @@ case net::HTTP_NOT_FOUND: reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; break; - case net::HTTP_PRECONDITION_FAILED: - // Failed our 'If-Unmodified-Since' or 'If-Match'; see - // download_manager_impl.cc BeginDownload() - reason = DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; - break; case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: // Retry by downloading from the start automatically: // If we haven't received data when we get this error, we won't.
diff --git a/content/browser/file_descriptor_info_impl.cc b/content/browser/file_descriptor_info_impl.cc index 45ce542..c6cf831 100644 --- a/content/browser/file_descriptor_info_impl.cc +++ b/content/browser/file_descriptor_info_impl.cc
@@ -4,6 +4,8 @@ #include "content/browser/file_descriptor_info_impl.h" +#include <utility> + namespace content { // static @@ -23,7 +25,7 @@ void FileDescriptorInfoImpl::Transfer(int id, base::ScopedFD fd) { AddToMapping(id, fd.get()); - owned_descriptors_.push_back(new base::ScopedFD(fd.Pass())); + owned_descriptors_.push_back(new base::ScopedFD(std::move(fd))); } base::PlatformFile FileDescriptorInfoImpl::GetFDAt(size_t i) const { @@ -65,7 +67,7 @@ (*found)->swap(fd); owned_descriptors_.erase(found); - return fd.Pass(); + return fd; } void FileDescriptorInfoImpl::AddToMapping(int id, base::PlatformFile fd) {
diff --git a/content/browser/file_descriptor_info_impl_unittest.cc b/content/browser/file_descriptor_info_impl_unittest.cc index 9724a7c..ccc061a 100644 --- a/content/browser/file_descriptor_info_impl_unittest.cc +++ b/content/browser/file_descriptor_info_impl_unittest.cc
@@ -6,6 +6,7 @@ #include <fcntl.h> #include <unistd.h> +#include <utility> #include "base/basictypes.h" #include "base/posix/eintr_wrapper.h" @@ -43,7 +44,7 @@ base::ScopedFD fd(GetSafeFd()); int raw_fd = fd.get(); - target->Transfer(testingId, fd.Pass()); + target->Transfer(testingId, std::move(fd)); ASSERT_EQ(1U, target->GetMappingSize()); ASSERT_EQ(target->GetFDAt(0), raw_fd); ASSERT_EQ(target->GetIDAt(0), testingId);
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc index be13119..dd23dae 100644 --- a/content/browser/geolocation/network_location_request.cc +++ b/content/browser/geolocation/network_location_request.cc
@@ -4,6 +4,9 @@ #include "content/browser/geolocation/network_location_request.h" +#include <stdint.h> + +#include <limits> #include <set> #include <string> @@ -209,11 +212,12 @@ const base::Time& timestamp, const base::string16& access_token, std::string* upload_data) { - int age = kint32min; // Invalid so AddInteger() will ignore. + int age = std::numeric_limits<int32_t>::min(); // Invalid so AddInteger() + // will ignore. if (!timestamp.is_null()) { // Convert absolute timestamps into a relative age. - int64 delta_ms = (base::Time::Now() - timestamp).InMilliseconds(); - if (delta_ms >= 0 && delta_ms < kint32max) + int64_t delta_ms = (base::Time::Now() - timestamp).InMilliseconds(); + if (delta_ms >= 0 && delta_ms < std::numeric_limits<int32_t>::max()) age = static_cast<int>(delta_ms); } @@ -234,7 +238,7 @@ void AddInteger(const std::string& property_name, int value, base::DictionaryValue* dict) { DCHECK(dict); - if (value != kint32min) + if (value != std::numeric_limits<int32_t>::min()) dict->SetInteger(property_name, value); }
diff --git a/content/browser/geolocation/network_location_request.h b/content/browser/geolocation/network_location_request.h index f0734e0..3b265e5 100644 --- a/content/browser/geolocation/network_location_request.h +++ b/content/browser/geolocation/network_location_request.h
@@ -5,7 +5,6 @@ #ifndef CONTENT_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_ #define CONTENT_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_ -#include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/browser/geolocation/wifi_data_provider.h"
diff --git a/content/browser/geolocation/wifi_data.cc b/content/browser/geolocation/wifi_data.cc index bcfb981..fd5a99b3 100644 --- a/content/browser/geolocation/wifi_data.cc +++ b/content/browser/geolocation/wifi_data.cc
@@ -4,17 +4,19 @@ #include "content/browser/geolocation/wifi_data.h" +#include <stdint.h> + #include <algorithm> +#include <limits> #include "base/logging.h" namespace content { AccessPointData::AccessPointData() - : radio_signal_strength(kint32min), - channel(kint32min), - signal_to_noise(kint32min) { -} + : radio_signal_strength(std::numeric_limits<int32_t>::min()), + channel(std::numeric_limits<int32_t>::min()), + signal_to_noise(std::numeric_limits<int32_t>::min()) {} AccessPointData::~AccessPointData() {}
diff --git a/content/browser/geolocation/wifi_data.h b/content/browser/geolocation/wifi_data.h index 72bc306..d6e0b33 100644 --- a/content/browser/geolocation/wifi_data.h +++ b/content/browser/geolocation/wifi_data.h
@@ -7,7 +7,6 @@ #include <set> -#include "base/basictypes.h" #include "base/strings/string16.h" #include "content/common/content_export.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index ced0ab6f..370da12 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -4,6 +4,8 @@ #include "content/browser/gpu/gpu_process_host.h" +#include <utility> + #include "base/base64.h" #include "base/base_switches.h" #include "base/basictypes.h" @@ -270,7 +272,7 @@ } #elif defined(OS_POSIX) - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN SandboxType GetSandboxType() override {
diff --git a/content/browser/media/webrtc_identity_store_unittest.cc b/content/browser/media/webrtc_identity_store_unittest.cc index b97808d..025e2f32 100644 --- a/content/browser/media/webrtc_identity_store_unittest.cc +++ b/content/browser/media/webrtc_identity_store_unittest.cc
@@ -49,8 +49,6 @@ webrtc_identity_store_->SetTaskRunnerForTesting(pool_owner_->pool()); } - ~WebRtcIdentityStoreTest() override { pool_owner_->pool()->Shutdown(); } - void SetValidityPeriod(base::TimeDelta validity_period) { webrtc_identity_store_->SetValidityPeriodForTesting(validity_period); }
diff --git a/content/browser/net/quota_policy_cookie_store_unittest.cc b/content/browser/net/quota_policy_cookie_store_unittest.cc index f7987c55..ca33d6e 100644 --- a/content/browser/net/quota_policy_cookie_store_unittest.cc +++ b/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -109,7 +109,6 @@ // tasks that block pool shutdown (e.g. |store_|'s cleanup) have run before // yielding control. pool_owner_->pool()->FlushForTesting(); - pool_owner_->pool()->Shutdown(); pool_owner_.reset(new base::SequencedWorkerPoolOwner(3, "Background Pool")); } @@ -119,7 +118,6 @@ void TearDown() override { DestroyStore(); - pool_owner_->pool()->Shutdown(); } TestBrowserThreadBundle bundle_;
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc index ae6c3ae..8069d354 100644 --- a/content/browser/plugin_process_host.cc +++ b/content/browser/plugin_process_host.cc
@@ -6,10 +6,9 @@ #if defined(OS_WIN) #include <windows.h> -#elif defined(OS_POSIX) -#include <utility> // for pair<> #endif +#include <utility> #include <vector> #include "base/base_switches.h" @@ -112,7 +111,7 @@ } #elif defined(OS_POSIX) - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN private:
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc index 4d87474..23ce9d0f 100644 --- a/content/browser/ppapi_plugin_process_host.cc +++ b/content/browser/ppapi_plugin_process_host.cc
@@ -5,6 +5,7 @@ #include "content/browser/ppapi_plugin_process_host.h" #include <string> +#include <utility> #include "base/base_switches.h" #include "base/command_line.h" @@ -98,7 +99,7 @@ .GetSwitchValueNative(switches::kPpapiPluginLauncher); return !is_broker_ && plugin_launcher.empty(); } - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN SandboxType GetSandboxType() override {
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 90d3241c..789c5ea3 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -97,9 +97,13 @@ void SwapBuffers(cc::CompositorFrame* frame) override { GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info); - DCHECK(frame->gl_frame_data->sub_buffer_rect == - gfx::Rect(frame->gl_frame_data->size)); - context_provider_->ContextSupport()->Swap(); + if (frame->gl_frame_data->sub_buffer_rect.IsEmpty()) { + context_provider_->ContextSupport()->CommitOverlayPlanes(); + } else { + DCHECK(frame->gl_frame_data->sub_buffer_rect == + gfx::Rect(frame->gl_frame_data->size)); + context_provider_->ContextSupport()->Swap(); + } client_->DidSwapBuffers(); } @@ -445,9 +449,8 @@ // TODO(enne): Update this this compositor to use the scheduler. settings.single_thread_proxy_scheduler = false; - if (command_line->HasSwitch( - switches::kEnableAndroidCompositorAnimationTimelines)) - settings.use_compositor_animation_timelines = true; + settings.use_compositor_animation_timelines = !command_line->HasSwitch( + switches::kDisableAndroidCompositorAnimationTimelines); cc::LayerTreeHost::InitParams params; params.client = this;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 03010414..4c2413e3 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include <limits> +#include <utility> #include <vector> #include "base/base_switches.h" @@ -394,7 +395,7 @@ browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix); return renderer_prefix.empty(); } - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN SandboxType GetSandboxType() override { return SANDBOX_TYPE_RENDERER; } @@ -2144,7 +2145,7 @@ // logic into IsSuitableHost, and check |url| against the URL the process is // dedicated to. This will allow pages from the same site to share, and will // also allow non-isolated sites to share processes. https://crbug.com/513036 - if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) + if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) return false; // NOTE: Sometimes it's necessary to create more render processes than
diff --git a/content/browser/tracing/tracing_resources.gyp b/content/browser/tracing/tracing_resources.gyp index d63e8d85..df12689 100644 --- a/content/browser/tracing/tracing_resources.gyp +++ b/content/browser/tracing/tracing_resources.gyp
@@ -12,6 +12,7 @@ # GN version: //content/browser/tracing:generate_tracing_grd 'target_name': 'generate_tracing_grd', 'type': 'none', + 'hard_dependency': 1, 'dependencies': [ '<(trace_viewer_src_dir)/trace_viewer.gyp:generate_about_tracing', ], @@ -41,6 +42,7 @@ # GN version: //content/browser/tracing:resources 'target_name': 'tracing_resources', 'type': 'none', + 'hard_dependency': 1, 'dependencies': [ '<(trace_viewer_src_dir)/trace_viewer.gyp:generate_about_tracing', 'generate_tracing_grd', @@ -76,6 +78,7 @@ }, 'inputs': [ '<(grit_grd_file)', + '<(DEPTH)/tools/gritsettings/resource_ids', '<!@pymod_do_main(grit_info --inputs)', ], 'outputs': [
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index 4e2b07c..4cd0cd1 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc
@@ -4,6 +4,8 @@ #include "content/browser/utility_process_host_impl.h" +#include <utility> + #include "base/base_switches.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -88,7 +90,7 @@ return !no_sandbox_ && exposed_dir_.empty(); } base::EnvironmentMap GetEnvironment() override { return env_; } - base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); } + base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); } #endif // OS_WIN SandboxType GetSandboxType() override {
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index 50c4be7..510c05b 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -25,6 +25,7 @@ #include "base/sys_info.h" #include "base/thread_task_runner_handle.h" #include "base/threading/platform_thread.h" +#include "base/threading/thread.h" #include "base/time/time.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/memory_dump_manager.h" @@ -458,7 +459,8 @@ BlinkPlatformImpl::BlinkPlatformImpl( scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) - : main_thread_task_runner_(main_thread_task_runner) { + : main_thread_task_runner_(main_thread_task_runner), + compositor_thread_(nullptr) { InternalInit(); } @@ -478,9 +480,11 @@ } } -void BlinkPlatformImpl::UpdateWebThreadTLS(blink::WebThread* thread) { +void BlinkPlatformImpl::UpdateWebThreadTLS(blink::WebThread* thread, + base::WaitableEvent* event) { DCHECK(!current_thread_slot_.Get()); current_thread_slot_.Set(thread); + event->Signal(); } BlinkPlatformImpl::~BlinkPlatformImpl() { @@ -545,11 +549,20 @@ } blink::WebThread* BlinkPlatformImpl::createThread(const char* name) { - scheduler::WebThreadImplForWorkerScheduler* thread = - new scheduler::WebThreadImplForWorkerScheduler(name); + return createThreadWithOptions(name, base::Thread::Options()).release(); +} + +scoped_ptr<scheduler::WebThreadBase> BlinkPlatformImpl::createThreadWithOptions( + const char* name, + base::Thread::Options options) { + scoped_ptr<scheduler::WebThreadBase> thread( + new scheduler::WebThreadImplForWorkerScheduler(name, options)); + base::WaitableEvent event(false, false); thread->TaskRunner()->PostTask( - FROM_HERE, base::Bind(&BlinkPlatformImpl::UpdateWebThreadTLS, - base::Unretained(this), thread)); + FROM_HERE, + base::Bind(&BlinkPlatformImpl::UpdateWebThreadTLS, base::Unretained(this), + base::Unretained(thread.get()), base::Unretained(&event))); + event.Wait(); return thread; } @@ -1119,6 +1132,10 @@ base::RandBytes(buffer, length); } +blink::WebThread* BlinkPlatformImpl::compositorThread() const { + return compositor_thread_; +} + blink::WebGestureCurve* BlinkPlatformImpl::createFlingAnimationCurve( blink::WebGestureDevice device_source, const blink::WebFloatPoint& velocity,
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index 5638234..b6850f24 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -30,6 +30,11 @@ namespace base { class MessageLoop; +class WaitableEvent; +} + +namespace scheduler { +class WebThreadBase; } namespace content { @@ -172,6 +177,7 @@ double systemTraceTime() override; void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override; + blink::WebThread* compositorThread() const override; blink::WebGestureCurve* createFlingAnimationCurve( blink::WebGestureDevice device_source, const blink::WebFloatPoint& velocity, @@ -192,9 +198,20 @@ blink::WebString domKeyStringFromEnum(int dom_key) override; int domKeyEnumFromString(const blink::WebString& key_string) override; + scoped_ptr<scheduler::WebThreadBase> createThreadWithOptions( + const char* name, + base::Thread::Options); + + // This class does *not* own |compositor_thread|. It is the responsibility of + // the caller to ensure that the compositor thread is cleared before it is + // destructed. + void set_compositor_thread(scheduler::WebThreadBase* compositor_thread) { + compositor_thread_ = compositor_thread; + } + private: void InternalInit(); - void UpdateWebThreadTLS(blink::WebThread* thread); + void UpdateWebThreadTLS(blink::WebThread* thread, base::WaitableEvent* event); bool IsMainThread() const; @@ -216,6 +233,8 @@ scoped_refptr<PushDispatcher> push_dispatcher_; scoped_ptr<PermissionDispatcher> permission_client_; scoped_ptr<BackgroundSyncProvider> main_thread_sync_provider_; + + scheduler::WebThreadBase* compositor_thread_; }; } // namespace content
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc index 3a04cb1..92a0962 100644 --- a/content/child/resource_dispatcher.cc +++ b/content/child/resource_dispatcher.cc
@@ -209,6 +209,9 @@ return; } + // TODO(erikchen): Temporary debugging. http://crbug.com/527588. + CHECK_GE(shm_size, 0); + CHECK_LE(shm_size, 512 * 1024); request_info->buffer_size = shm_size; } @@ -224,6 +227,14 @@ CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle())); CHECK_GE(request_info->buffer_size, data_offset + data_length); + // TODO(erikchen): Temporary debugging. http://crbug.com/527588. + CHECK_GE(request_info->buffer_size, 0); + CHECK_LE(request_info->buffer_size, 512 * 1024); + CHECK_GE(data_length, 0); + CHECK_LE(data_length, 512 * 1024); + CHECK_GE(data_offset, 0); + CHECK_LE(data_offset, 512 * 1024); + // Ensure that the SHM buffer remains valid for the duration of this scope. // It is possible for Cancel() to be called before we exit this scope. // SharedMemoryReceivedDataFactory stores the SHM buffer inside it.
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index f8559b9..575dce7 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc
@@ -613,7 +613,7 @@ // that it gets closed after it has been sent. base::ScopedFD renderer_fd = channel_->TakeClientFileDescriptor(); DCHECK(renderer_fd.is_valid()); - channel_handle.socket = base::FileDescriptor(renderer_fd.Pass()); + channel_handle.socket = base::FileDescriptor(std::move(renderer_fd)); #endif channel_->AddFilter(filter_.get());
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc index 33ac9a7..46e9dce 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator.cc +++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc
@@ -795,11 +795,11 @@ "Failed to query DX11 device context from ANGLE device", false); - // Enable multithreaded mode on the context. This ensures that accesses to + // Enable multithreaded mode on the device. This ensures that accesses to // context are synchronized across threads. We have multiple threads // accessing the context, the media foundation decoder threads and the // decoder thread via the video format conversion transform. - hr = multi_threaded_.QueryFrom(d3d11_device_context_.get()); + hr = multi_threaded_.QueryFrom(angle_device.get()); RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); multi_threaded_->SetMultithreadProtected(TRUE);
diff --git a/content/common/sandbox_linux/sandbox_init_linux.cc b/content/common/sandbox_linux/sandbox_init_linux.cc index 146b352..9ffeb5d 100644 --- a/content/common/sandbox_linux/sandbox_init_linux.cc +++ b/content/common/sandbox_linux/sandbox_init_linux.cc
@@ -4,6 +4,8 @@ #include "content/public/common/sandbox_init.h" +#include <utility> + #include "base/files/scoped_file.h" #include "base/memory/scoped_ptr.h" #include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h" @@ -14,7 +16,7 @@ bool InitializeSandbox(scoped_ptr<sandbox::bpf_dsl::Policy> policy, base::ScopedFD proc_fd) { return SandboxSeccompBPF::StartSandboxWithExternalPolicy(policy.Pass(), - proc_fd.Pass()); + std::move(proc_fd)); } #if !defined(OS_NACL_NONSFI)
diff --git a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc index 79adbee..de2bcc0 100644 --- a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc +++ b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
@@ -70,7 +70,7 @@ // doing so does not stop the sandbox. SandboxBPF sandbox(policy); - sandbox.SetProcFd(proc_fd.Pass()); + sandbox.SetProcFd(std::move(proc_fd)); CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED)); } @@ -201,7 +201,7 @@ } CHECK(policy->PreSandboxHook()); - StartSandboxWithPolicy(policy.release(), proc_fd.Pass()); + StartSandboxWithPolicy(policy.release(), std::move(proc_fd)); RunSandboxSanityChecks(process_type); return true; @@ -279,7 +279,7 @@ // If the kernel supports the sandbox, and if the command line says we // should enable it, enable it or die. bool started_sandbox = - StartBPFSandbox(command_line, process_type, proc_fd.Pass()); + StartBPFSandbox(command_line, process_type, std::move(proc_fd)); CHECK(started_sandbox); return true; } @@ -294,7 +294,7 @@ #if defined(USE_SECCOMP_BPF) if (IsSeccompBPFDesired() && SupportsSandbox()) { CHECK(policy); - StartSandboxWithPolicy(policy.release(), proc_fd.Pass()); + StartSandboxWithPolicy(policy.release(), std::move(proc_fd)); return true; } #endif // defined(USE_SECCOMP_BPF)
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index 07769f4..9462cc4d 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi
@@ -62,6 +62,7 @@ '../media/media.gyp:media', '../net/net.gyp:net', '../net/net.gyp:net_resources', + '../ppapi/ppapi_internal.gyp:blink_test_plugin', '../skia/skia.gyp:skia', '../storage/storage_browser.gyp:storage', '../third_party/WebKit/public/blink.gyp:blink', @@ -735,6 +736,14 @@ ], 'copies': [ { + # PPAPI test plugins are loaded relative to DIR_MODULE. On OS X, + # that corresponds to Content Shell Framework.framework. + 'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)', + 'files': [ + '<(PRODUCT_DIR)/blink_test_plugin.plugin', + ], + }, + { 'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Resources', 'files': [ '<(PRODUCT_DIR)/crash_inspector',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 8a44a71..2e9ec20 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -359,6 +359,8 @@ 'browser/background_sync/background_sync_network_observer_unittest.cc', 'browser/background_sync/background_sync_power_observer_unittest.cc', 'browser/background_sync/background_sync_service_impl_unittest.cc', + 'browser/blob_storage/blob_async_builder_host_unittest.cc', + 'browser/blob_storage/blob_async_transport_strategy_unittest.cc', 'browser/blob_storage/blob_storage_registry_unittest.cc', 'browser/browser_io_surface_manager_mac_unittest.cc', 'browser/browser_thread_unittest.cc',
diff --git a/content/public/browser/download_interrupt_reason_values.h b/content/public/browser/download_interrupt_reason_values.h index 92687b6..95c4f4a 100644 --- a/content/public/browser/download_interrupt_reason_values.h +++ b/content/public/browser/download_interrupt_reason_values.h
@@ -86,9 +86,12 @@ // Internal use only: must restart from the beginning. INTERRUPT_REASON(SERVER_NO_RANGE, 31) -// The download request does not meet the specified precondition. -// Internal use only: the file has changed on the server. -INTERRUPT_REASON(SERVER_PRECONDITION, 32) +// Precondition failed. This type of interruption could legitimately occur if a +// partial download resumption was attempted using a If-Match header. However, +// the downloads logic no longer uses If-Match headers and instead uses If-Range +// headers where a precondition failure is not expected. +// +// Obsolete: INTERRUPT_REASON(SERVER_PRECONDITION, 32) // The server does not have the requested data. // "Unable to get file".
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index f0740b4..35708aea 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -882,6 +882,11 @@ #endif #if defined(OS_ANDROID) +// Disable external animation system for Android compositor. +// See also kDisableCompositorAnimationTimelines for renderer compositors. +const char kDisableAndroidCompositorAnimationTimelines[] = + "disable-android-compositor-animation-timelines"; + // Disable overscroll edge effects like those found in Android views. const char kDisableOverscrollEdgeEffect[] = "disable-overscroll-edge-effect"; @@ -896,11 +901,6 @@ const char kEnableAdaptiveSelectionHandleOrientation[] = "enable-adaptive-selection-handle-orientation"; -// Enable external animation system for Android compositor. -// See also kEnableCompositorAnimationTimelines for renderer compositors. -const char kEnableAndroidCompositorAnimationTimelines[] = - "enable-android-compositor-animation-timelines"; - // Enable drag manipulation of longpress-triggered text selections. const char kEnableLongpressDragSelection[] = "enable-longpress-drag-selection";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 2cf8146..2533f42a 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -258,11 +258,11 @@ #endif #if defined(OS_ANDROID) +CONTENT_EXPORT extern const char kDisableAndroidCompositorAnimationTimelines[]; CONTENT_EXPORT extern const char kDisableOverscrollEdgeEffect[]; CONTENT_EXPORT extern const char kDisablePullToRefreshEffect[]; CONTENT_EXPORT extern const char kDisableScreenOrientationLock[]; CONTENT_EXPORT extern const char kEnableAdaptiveSelectionHandleOrientation[]; -CONTENT_EXPORT extern const char kEnableAndroidCompositorAnimationTimelines[]; CONTENT_EXPORT extern const char kEnableLongpressDragSelection[]; CONTENT_EXPORT extern const char kIPCSyncCompositing[]; CONTENT_EXPORT extern const char kHideScrollbars[];
diff --git a/content/public/test/ppapi_test_utils.cc b/content/public/test/ppapi_test_utils.cc index 0c9e545..6078594 100644 --- a/content/public/test/ppapi_test_utils.cc +++ b/content/public/test/ppapi_test_utils.cc
@@ -18,7 +18,8 @@ bool RegisterPlugin( base::CommandLine* command_line, const base::FilePath::StringType& library_name, - const base::FilePath::StringType& extra_registration_parameters) { + const base::FilePath::StringType& extra_registration_parameters, + const base::FilePath::StringType& mime_type) { base::FilePath plugin_dir; if (!PathService::Get(base::DIR_MODULE, &plugin_dir)) return false; @@ -30,12 +31,22 @@ return false; base::FilePath::StringType pepper_plugin = plugin_path.value(); pepper_plugin.append(extra_registration_parameters); - pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests")); + pepper_plugin.append(FILE_PATH_LITERAL(";")); + pepper_plugin.append(mime_type); command_line->AppendSwitchNative(switches::kRegisterPepperPlugins, pepper_plugin); return true; } +bool RegisterPluginWithDefaultMimeType( + base::CommandLine* command_line, + const base::FilePath::StringType& library_name, + const base::FilePath::StringType& extra_registration_parameters) { + return RegisterPlugin(command_line, library_name, + extra_registration_parameters, + FILE_PATH_LITERAL("application/x-ppapi-tests")); +} + } // namespace bool RegisterTestPlugin(base::CommandLine* command_line) { @@ -53,14 +64,32 @@ #elif defined(OS_POSIX) base::FilePath::StringType plugin_library = "libppapi_tests.so"; #endif - return RegisterPlugin(command_line, plugin_library, - extra_registration_parameters); + return RegisterPluginWithDefaultMimeType(command_line, plugin_library, + extra_registration_parameters); } bool RegisterPowerSaverTestPlugin(base::CommandLine* command_line) { base::FilePath::StringType library_name = base::FilePath::FromUTF8Unsafe(ppapi::kPowerSaverTestPluginName).value(); - return RegisterPlugin(command_line, library_name, FILE_PATH_LITERAL("")); + return RegisterPluginWithDefaultMimeType(command_line, library_name, + FILE_PATH_LITERAL("")); } +bool RegisterBlinkTestPlugin(base::CommandLine* command_line) { +#if defined(OS_WIN) + static const base::FilePath::CharType kPluginLibrary[] = + L"blink_test_plugin.dll"; +#elif defined(OS_MACOSX) + static const base::FilePath::CharType kPluginLibrary[] = + "blink_test_plugin.plugin"; +#elif defined(OS_POSIX) + static const base::FilePath::CharType kPluginLibrary[] = + "libblink_test_plugin.so"; +#endif + // #name#description#version + static const base::FilePath::CharType kExtraParameters[] = + FILE_PATH_LITERAL("#Blink Test Plugin#Interesting description.#0.8"); + return RegisterPlugin(command_line, kPluginLibrary, kExtraParameters, + FILE_PATH_LITERAL("application/x-blink-test-plugin")); +} } // namespace ppapi
diff --git a/content/public/test/ppapi_test_utils.h b/content/public/test/ppapi_test_utils.h index 1341840..103e0e0 100644 --- a/content/public/test/ppapi_test_utils.h +++ b/content/public/test/ppapi_test_utils.h
@@ -32,6 +32,10 @@ bool RegisterPowerSaverTestPlugin(base::CommandLine* command_line) WARN_UNUSED_RESULT; +// Registers the Blink test plugin to application/x-blink-test-plugin. +bool RegisterBlinkTestPlugin(base::CommandLine* command_line) + WARN_UNUSED_RESULT; + } // namespace ppapi #endif // CONTENT_PUBLIC_TEST_PPAPI_TEST_UTILS_H_
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc index 4368ab4..5dc4c68 100644 --- a/content/renderer/dom_serializer_browsertest.cc +++ b/content/renderer/dom_serializer_browsertest.cc
@@ -31,6 +31,7 @@ #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebElementCollection.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebMetaElement.h" #include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebPageSerializer.h" #include "third_party/WebKit/public/web/WebPageSerializerClient.h" @@ -40,6 +41,7 @@ using blink::WebData; using blink::WebDocument; using blink::WebElement; +using blink::WebMetaElement; using blink::WebElementCollection; using blink::WebFrame; using blink::WebLocalFrame; @@ -57,59 +59,6 @@ return doc.firstChild().isDocumentTypeNode(); } -// Helper function for checking whether input node is META tag. Return true -// means it is META element, otherwise return false. The parameter charset_info -// return actual charset info if the META tag has charset declaration. -bool IsMetaElement(const WebNode& node, std::string& charset_info) { - if (!node.isElementNode()) - return false; - const WebElement meta = node.toConst<WebElement>(); - if (!meta.hasHTMLTagName("meta")) - return false; - charset_info.erase(0, charset_info.length()); - // Check the META charset declaration. - WebString httpEquiv = meta.getAttribute("http-equiv"); - if (base::LowerCaseEqualsASCII(base::StringPiece16(httpEquiv), - "content-type")) { - std::string content = meta.getAttribute("content").utf8(); - int pos = content.find("charset", 0); - if (pos > -1) { - // Add a dummy charset declaration to charset_info, which indicates this - // META tag has charset declaration although we do not get correct value - // yet. - charset_info.append("has-charset-declaration"); - int remaining_length = content.length() - pos - 7; - if (!remaining_length) - return true; - int start_pos = pos + 7; - // Find "=" symbol. - while (remaining_length--) - if (content[start_pos++] == L'=') - break; - // Skip beginning space. - while (remaining_length) { - if (content[start_pos] > 0x0020) - break; - ++start_pos; - --remaining_length; - } - if (!remaining_length) - return true; - int end_pos = start_pos; - // Now we find out the start point of charset info. Search the end point. - while (remaining_length--) { - if (content[end_pos] <= 0x0020 || content[end_pos] == L';') - break; - ++end_pos; - } - // Get actual charset info. - charset_info = content.substr(start_pos, end_pos - start_pos); - return true; - } - } - return true; -} - class LoadObserver : public RenderViewObserver { public: LoadObserver(RenderView* render_view, const base::Closure& quit_closure) @@ -300,11 +249,11 @@ WebElement head_element = doc.head(); ASSERT_TRUE(!head_element.isNull()); // Go through all children of HEAD element. - for (WebNode child = head_element.firstChild(); !child.isNull(); - child = child.nextSibling()) { - std::string charset_info; - if (IsMetaElement(child, charset_info)) - ASSERT_TRUE(charset_info.empty()); + WebElementCollection meta_elements = head_element. + getElementsByHTMLTagName("meta"); + for (WebElement element = meta_elements.firstItem(); !element.isNull(); + element = meta_elements.nextItem()) { + ASSERT_TRUE(element.to<WebMetaElement>().computeEncoding().isEmpty()); } // Do serialization. SerializeDomForURL(file_url); @@ -321,21 +270,19 @@ ASSERT_TRUE(doc.isHTMLDocument()); head_element = doc.head(); ASSERT_TRUE(!head_element.isNull()); - WebNode meta_node = head_element.firstChild(); - ASSERT_TRUE(!meta_node.isNull()); - // Get meta charset info. - std::string charset_info2; - ASSERT_TRUE(IsMetaElement(meta_node, charset_info2)); - ASSERT_TRUE(!charset_info2.empty()); - ASSERT_EQ(charset_info2, - std::string(web_frame->document().encoding().utf8())); + ASSERT_TRUE(!head_element.firstChild().isNull()); + ASSERT_TRUE(head_element.firstChild().isElementNode()); + WebMetaElement meta_element = head_element.firstChild(). + to<WebMetaElement>(); + ASSERT_EQ(meta_element.computeEncoding(), web_frame->document().encoding()); // Make sure no more additional META tags which have charset declaration. - for (WebNode child = meta_node.nextSibling(); !child.isNull(); - child = child.nextSibling()) { - std::string charset_info; - if (IsMetaElement(child, charset_info)) - ASSERT_TRUE(charset_info.empty()); + meta_elements = head_element.getElementsByHTMLTagName("meta"); + for (WebElement element = meta_elements.firstItem(); !element.isNull(); + element = meta_elements.nextItem()) { + if (element == meta_element) + continue; + ASSERT_TRUE(element.to<WebMetaElement>().computeEncoding().isEmpty()); } } @@ -347,15 +294,16 @@ ASSERT_TRUE(web_frame != NULL); WebDocument doc = web_frame->document(); ASSERT_TRUE(doc.isHTMLDocument()); - WebElement head_ele = doc.head(); - ASSERT_TRUE(!head_ele.isNull()); + WebElement head_element = doc.head(); + ASSERT_TRUE(!head_element.isNull()); // Go through all children of HEAD element. int charset_declaration_count = 0; - for (WebNode child = head_ele.firstChild(); !child.isNull(); - child = child.nextSibling()) { - std::string charset_info; - if (IsMetaElement(child, charset_info) && !charset_info.empty()) - charset_declaration_count++; + WebElementCollection meta_elements = head_element. + getElementsByHTMLTagName("meta"); + for (WebElement element = meta_elements.firstItem(); !element.isNull(); + element = meta_elements.nextItem()) { + if (!element.to<WebMetaElement>().computeEncoding().isEmpty()) + ++charset_declaration_count; } // The original doc has more than META tags which have charset declaration. ASSERT_TRUE(charset_declaration_count > 1); @@ -373,23 +321,21 @@ ASSERT_TRUE(web_frame != NULL); doc = web_frame->document(); ASSERT_TRUE(doc.isHTMLDocument()); - head_ele = doc.head(); - ASSERT_TRUE(!head_ele.isNull()); - WebNode meta_node = head_ele.firstChild(); - ASSERT_TRUE(!meta_node.isNull()); - // Get meta charset info. - std::string charset_info2; - ASSERT_TRUE(IsMetaElement(meta_node, charset_info2)); - ASSERT_TRUE(!charset_info2.empty()); - ASSERT_EQ(charset_info2, - std::string(web_frame->document().encoding().utf8())); + head_element = doc.head(); + ASSERT_TRUE(!head_element.isNull()); + ASSERT_TRUE(!head_element.firstChild().isNull()); + ASSERT_TRUE(head_element.firstChild().isElementNode()); + WebMetaElement meta_element = head_element.firstChild(). + to<WebMetaElement>(); + ASSERT_EQ(meta_element.computeEncoding(), web_frame->document().encoding()); // Make sure no more additional META tags which have charset declaration. - for (WebNode child = meta_node.nextSibling(); !child.isNull(); - child = child.nextSibling()) { - std::string charset_info; - if (IsMetaElement(child, charset_info)) - ASSERT_TRUE(charset_info.empty()); + meta_elements = head_element.getElementsByHTMLTagName("meta"); + for (WebElement element = meta_elements.firstItem(); !element.isNull(); + element = meta_elements.nextItem()) { + if (element == meta_element) + continue; + ASSERT_TRUE(element.to<WebMetaElement>().computeEncoding().isEmpty()); } } @@ -637,15 +583,12 @@ ASSERT_TRUE(doc.isHTMLDocument()); head_element = doc.head(); ASSERT_TRUE(!head_element.isNull()); - WebNode meta_node = head_element.firstChild(); - ASSERT_TRUE(!meta_node.isNull()); - ASSERT_TRUE(meta_node.nextSibling().isNull()); - // Get meta charset info. - std::string charset_info; - ASSERT_TRUE(IsMetaElement(meta_node, charset_info)); - ASSERT_TRUE(!charset_info.empty()); - ASSERT_EQ(charset_info, - std::string(web_frame->document().encoding().utf8())); + ASSERT_TRUE(!head_element.firstChild().isNull()); + ASSERT_TRUE(head_element.firstChild().isElementNode()); + ASSERT_TRUE(head_element.firstChild().nextSibling().isNull()); + WebMetaElement meta_element = head_element.firstChild(). + to<WebMetaElement>(); + ASSERT_EQ(meta_element.computeEncoding(), web_frame->document().encoding()); // Check the body's first node is text node and its contents are // "hello world" @@ -653,8 +596,7 @@ ASSERT_TRUE(!body_element.isNull()); WebNode text_node = body_element.firstChild(); ASSERT_TRUE(text_node.isTextNode()); - WebString text_node_contents = text_node.nodeValue(); - ASSERT_TRUE(std::string(text_node_contents.utf8()) == "hello world"); + ASSERT_EQ("hello world", text_node.nodeValue()); } void SubResourceForElementsInNonHTMLNamespaceOnRenderer(
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc index aa2a2ec..f7393c1d 100644 --- a/content/renderer/media/rtc_peer_connection_handler.cc +++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -32,6 +32,7 @@ #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/media/webrtc_uma_histograms.h" #include "content/renderer/render_thread_impl.h" +#include "media/base/media_switches.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" #include "third_party/WebKit/public/platform/WebRTCConfiguration.h" #include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h" @@ -872,6 +873,9 @@ webrtc::PeerConnectionInterface::RTCConfiguration config; GetNativeRtcConfiguration(server_configuration, &config); + config.disable_prerenderer_smoothing = + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableRTCSmoothnessAlgorithm); RTCMediaConstraints constraints(options);
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc index cc65808..34c72c40 100644 --- a/content/renderer/pepper/event_conversion.cc +++ b/content/renderer/pepper/event_conversion.cc
@@ -135,14 +135,8 @@ InputEventData result = GetEventWithCommonFieldsAndType(event); result.event_modifiers = key_event.modifiers; result.key_code = key_event.windowsKeyCode; -#if defined(OS_MACOSX) - // Workaround for |domCode| not being set on OS X. crbug.com/493833 - result.code = ui::KeycodeConverter::DomCodeToCodeString( - ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.nativeKeyCode)); -#else result.code = ui::KeycodeConverter::DomCodeToCodeString( static_cast<ui::DomCode>(key_event.domCode)); -#endif result_events->push_back(result); }
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index a3ecc9a..811c107 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1079,7 +1079,7 @@ event.type == blink::WebInputEvent::MouseDown && (event.modifiers & blink::WebInputEvent::LeftButtonDown)) { has_been_clicked_ = true; - blink::WebRect bounds = container()->element().boundsInViewportSpace(); + blink::WebRect bounds = container()->element().boundsInViewport(); RecordFlashClickSizeMetric(bounds.width, bounds.height); }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index bf5b570..992825b 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -39,7 +39,9 @@ #include "cc/blink/web_layer_impl.h" #include "cc/layers/layer_settings.h" #include "cc/raster/task_graph_runner.h" +#include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_settings.h" +#include "components/scheduler/child/webthread_base.h" #include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/appcache/appcache_frontend_impl.h" @@ -846,6 +848,8 @@ media_thread_.reset(); + blink_platform_impl_->set_compositor_thread(nullptr); + compositor_thread_.reset(); // AudioMessageFilter may be accessed on |media_thread_|, so shutdown after. @@ -1052,6 +1056,60 @@ resource_dispatcher()->SetMainThreadTaskRunner(resource_task_queue); } +void RenderThreadImpl::InitializeCompositorThread() { +#if defined(OS_ANDROID) + SynchronousCompositorFactory* sync_compositor_factory = + SynchronousCompositorFactory::GetInstance(); + bool using_ipc_sync_compositing = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kIPCSyncCompositing); + DCHECK(!sync_compositor_factory || !using_ipc_sync_compositing); + + if (sync_compositor_factory) { + compositor_task_runner_ = + sync_compositor_factory->GetCompositorTaskRunner(); + } +#endif + if (!compositor_task_runner_.get()) { + base::Thread::Options options; +#if defined(OS_ANDROID) + options.priority = base::ThreadPriority::DISPLAY; +#endif + compositor_thread_ = + blink_platform_impl_->createThreadWithOptions("Compositor", options); + compositor_task_runner_ = compositor_thread_->TaskRunner(); + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed), + false)); + blink_platform_impl_->set_compositor_thread(compositor_thread_.get()); + } + + InputHandlerManagerClient* input_handler_manager_client = NULL; +#if defined(OS_ANDROID) + if (using_ipc_sync_compositing) { + sync_compositor_message_filter_ = + new SynchronousCompositorFilter(compositor_task_runner_); + AddFilter(sync_compositor_message_filter_.get()); + input_handler_manager_client = sync_compositor_message_filter_.get(); + } else if (sync_compositor_factory) { + input_handler_manager_client = + sync_compositor_factory->GetInputHandlerManagerClient(); + } +#endif + if (!input_handler_manager_client) { + scoped_refptr<InputEventFilter> compositor_input_event_filter( + new InputEventFilter(main_input_callback_.callback(), + main_thread_compositor_task_runner_, + compositor_task_runner_)); + input_handler_manager_client = compositor_input_event_filter.get(); + input_event_filter_ = compositor_input_event_filter; + } + input_handler_manager_.reset(new InputHandlerManager( + compositor_task_runner_, input_handler_manager_client, + renderer_scheduler_.get())); +} + void RenderThreadImpl::EnsureWebKitInitialized() { if (blink_platform_impl_) return; @@ -1082,60 +1140,8 @@ base::Unretained(this))); SetResourceDispatchTaskQueue(renderer_scheduler_->LoadingTaskRunner()); - - bool enable = !command_line.HasSwitch(switches::kDisableThreadedCompositing); - if (enable) { -#if defined(OS_ANDROID) - SynchronousCompositorFactory* sync_compositor_factory = - SynchronousCompositorFactory::GetInstance(); - bool using_ipc_sync_compositing = - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kIPCSyncCompositing); - DCHECK(!sync_compositor_factory || !using_ipc_sync_compositing); - - if (sync_compositor_factory) { - compositor_task_runner_ = - sync_compositor_factory->GetCompositorTaskRunner(); - } -#endif - if (!compositor_task_runner_) { - compositor_thread_.reset(new base::Thread("Compositor")); - base::Thread::Options compositor_thread_options; -#if defined(OS_ANDROID) - compositor_thread_options.priority = base::ThreadPriority::DISPLAY; -#endif - compositor_thread_->StartWithOptions(compositor_thread_options); - compositor_task_runner_ = compositor_thread_->task_runner(); - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed), - false)); - } - - InputHandlerManagerClient* input_handler_manager_client = NULL; -#if defined(OS_ANDROID) - if (using_ipc_sync_compositing) { - sync_compositor_message_filter_ = - new SynchronousCompositorFilter(compositor_task_runner_); - AddFilter(sync_compositor_message_filter_.get()); - input_handler_manager_client = sync_compositor_message_filter_.get(); - } else if (sync_compositor_factory) { - input_handler_manager_client = - sync_compositor_factory->GetInputHandlerManagerClient(); - } -#endif - if (!input_handler_manager_client) { - scoped_refptr<InputEventFilter> compositor_input_event_filter( - new InputEventFilter(main_input_callback_.callback(), - main_thread_compositor_task_runner_, - compositor_task_runner_)); - input_handler_manager_client = compositor_input_event_filter.get(); - input_event_filter_ = compositor_input_event_filter; - } - input_handler_manager_.reset(new InputHandlerManager( - compositor_task_runner_, input_handler_manager_client, - renderer_scheduler_.get())); - } + if (!command_line.HasSwitch(switches::kDisableThreadedCompositing)) + InitializeCompositorThread(); if (!input_event_filter_.get()) { // Always provide an input event filter implementation to ensure consistent @@ -1148,7 +1154,7 @@ AddFilter(input_event_filter_.get()); scoped_refptr<base::SingleThreadTaskRunner> compositor_impl_side_task_runner; - if (enable) + if (compositor_task_runner_) compositor_impl_side_task_runner = compositor_task_runner_; else compositor_impl_side_task_runner = base::ThreadTaskRunnerHandle::Get();
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index ad108dc..f2292f5f 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -72,6 +72,7 @@ namespace scheduler { class RendererScheduler; +class WebThreadBase; } namespace v8 { @@ -464,6 +465,8 @@ void Init(); + void InitializeCompositorThread(); + void OnCreateNewFrame(FrameMsg_NewFrame_Params params); void OnCreateNewFrameProxy(int routing_id, int render_view_routing_id, @@ -588,7 +591,7 @@ scoped_ptr<base::Thread> file_thread_; // May be null if overridden by ContentRendererClient. - scoped_ptr<base::Thread> compositor_thread_; + scoped_ptr<scheduler::WebThreadBase> compositor_thread_; // Utility class to provide GPU functionalities to media. scoped_ptr<content::RendererGpuVideoAcceleratorFactories> gpu_factories_;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 8bb66f1..a645535 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1941,7 +1941,7 @@ bool is_editable = false; if (!toNode.isNull() && toNode.isElementNode()) { WebElement element = const_cast<WebNode&>(toNode).to<WebElement>(); - node_bounds = gfx::Rect(element.boundsInViewportSpace()); + node_bounds = gfx::Rect(element.boundsInViewport()); is_editable = element.isEditable(); } Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, is_editable,
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 9178ec8..c07b2156 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -237,7 +237,10 @@ #'copy_test_netscape_plugin', TODO(GYP) ] if (enable_plugins) { - deps += [ "//content/ppapi_plugin" ] + deps += [ + "//content/ppapi_plugin", + "//ppapi:blink_test_plugin", + ] } if (is_win) { @@ -453,7 +456,7 @@ if (is_win) { # GYP version: content/content_shell_and_tests.gyp:content_shell_crash_service - executable("crash_service") { + executable("content_shell_crash_service") { sources = [ "tools/content_shell_crash_service.cc", ]
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn index bbffa73..3c6af4d 100644 --- a/content/shell/android/BUILD.gn +++ b/content/shell/android/BUILD.gn
@@ -111,16 +111,13 @@ "//content/public/android:content_java", "//media/base/android:media_java", "//net/android:net_java", - - #"//third_party/mesa:osmesa_in_lib_dir", + "//third_party/mesa:osmesa", "//ui/android:ui_java", ] apk_name = "ContentShell" android_manifest = content_shell_manifest native_libs = [ "libcontent_shell_content_view.so" ] - - # TODO(GYP) - #'extra_native_libs': ['<(SHARED_LIB_DIR)/libosmesa.so'], + loadable_modules = [ "$root_out_dir/libosmesa.so" ] } android_library("content_shell_test_java") {
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc index bc1be22..fa6993b0 100644 --- a/content/shell/app/shell_main_delegate.cc +++ b/content/shell/app/shell_main_delegate.cc
@@ -20,6 +20,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" #include "content/public/test/layouttest_support.h" +#include "content/public/test/ppapi_test_utils.h" #include "content/shell/app/shell_crash_reporter_client.h" #include "content/shell/browser/layout_test/layout_test_browser_main.h" #include "content/shell/browser/layout_test/layout_test_content_browser_client.h" @@ -120,6 +121,9 @@ bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); + int dummy; + if (!exit_code) + exit_code = &dummy; #if defined(OS_WIN) // Enable trace control and transport through event tracing for Windows. @@ -141,8 +145,7 @@ // continue and try to load the fonts in BlinkTestPlatformInitialize // below, and then try to bring up the rest of the content module. if (!test_runner::CheckLayoutSystemDeps()) { - if (exit_code) - *exit_code = 1; + *exit_code = 1; return true; } } @@ -150,6 +153,12 @@ if (command_line.HasSwitch(switches::kRunLayoutTest)) { EnableBrowserLayoutTestMode(); +#if defined(ENABLE_PLUGINS) + if (!ppapi::RegisterBlinkTestPlugin(&command_line)) { + *exit_code = 1; + return true; + } +#endif command_line.AppendSwitch(switches::kProcessPerTab); command_line.AppendSwitch(switches::kEnableLogging); command_line.AppendSwitch(switches::kAllowFileAccessFromFiles); @@ -198,8 +207,7 @@ #endif if (!test_runner::BlinkTestPlatformInitialize()) { - if (exit_code) - *exit_code = 1; + *exit_code = 1; return true; } }
diff --git a/content/shell/browser/shell_plugin_service_filter.cc b/content/shell/browser/shell_plugin_service_filter.cc index f9cd7b9..204bb99 100644 --- a/content/shell/browser/shell_plugin_service_filter.cc +++ b/content/shell/browser/shell_plugin_service_filter.cc
@@ -20,7 +20,8 @@ const GURL& url, const GURL& policy_url, WebPluginInfo* plugin) { - return plugin->name == base::ASCIIToUTF16("WebKit Test PlugIn"); + return plugin->name == base::ASCIIToUTF16("Blink Test Plugin") || + plugin->name == base::ASCIIToUTF16("WebKit Test PlugIn"); } bool ShellPluginServiceFilter::CanLoadPlugin(int render_process_id,
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 0f210d29..00b1dad 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -96,9 +96,6 @@ self.Skip('conformance2/textures/webgl_canvas/*', bug=483282) self.Fail('conformance2/textures/misc/tex-storage-2d.html', bug=483282) - # Remove after we roll in https://github.com/KhronosGroup/WebGL/pull/1342. - self.Fail('conformance2/state/gl-get-calls.html', bug=483282) - # Windows only. self.Skip('deqp/functional/gles3/readpixel.html', ['win'], bug=483282) self.Skip('deqp/functional/gles3/texturestatequery.html',
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc index 929527e..d582eb1 100644 --- a/content/zygote/zygote_linux.cc +++ b/content/zygote/zygote_linux.cc
@@ -13,6 +13,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> +#include <utility> #include "base/command_line.h" #include "base/files/file_util.h" @@ -589,7 +590,7 @@ // First FD is the PID oracle socket. if (fds.size() < 1) return -1; - base::ScopedFD pid_oracle(fds[0]->Pass()); + base::ScopedFD pid_oracle(std::move(*fds[0])); // Remaining FDs are for the global descriptor mapping. for (int i = 1; i < numfds; ++i) { @@ -603,13 +604,9 @@ static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); // Returns twice, once per process. - base::ProcessId child_pid = ForkWithRealPid(process_type, - mapping, - channel_id, - pid_oracle.Pass(), - uma_name, - uma_sample, - uma_boundary_value); + base::ProcessId child_pid = + ForkWithRealPid(process_type, mapping, channel_id, std::move(pid_oracle), + uma_name, uma_sample, uma_boundary_value); if (!child_pid) { // This is the child process.
diff --git a/docs/clang_static_analyzer.md b/docs/clang_static_analyzer.md index 0ddf786..ed9feab9 100644 --- a/docs/clang_static_analyzer.md +++ b/docs/clang_static_analyzer.md
@@ -13,7 +13,7 @@ to get that is to run ```shell -tools/clang/scripts/update.sh --force-local-build --without-android +tools/clang/scripts/update.py --force-local-build --without-android ``` ## With make
diff --git a/docs/clang_tool_refactoring.md b/docs/clang_tool_refactoring.md index 929d8a27..8c23aa0 100644 --- a/docs/clang_tool_refactoring.md +++ b/docs/clang_tool_refactoring.md
@@ -25,8 +25,8 @@ or later): ```shell -tools/clang/scripts/update.sh --force-local-build --without-android \ ---with-chrome-tools <tools> +tools/clang/scripts/update.py --force-local-build --without-android \ +--tools <tools> ``` `<tools>` is a semicolon delimited list of subdirectories in `tools/clang` to @@ -35,8 +35,8 @@ plugin and the empty\_string tool, run the following: ```shell -tools/clang/scripts/update.sh --force-local-build --without-android \ ---with-chrome-tools "plugins;empty_string" +tools/clang/scripts/update.py --force-local-build --without-android \ +--tools plugins empty_string ``` When writing AST matchers, the following can be helpful to see what clang thinks
diff --git a/docs/linux_chromium_arm.md b/docs/linux_chromium_arm.md index ea465d44..da5114c8 100644 --- a/docs/linux_chromium_arm.md +++ b/docs/linux_chromium_arm.md
@@ -4,13 +4,7 @@ ## Recipe1: Building for an ARM CrOS device -This recipe uses `ninja` (instead of `make`) so its startup time is much lower -(sub-1s, instead of tens of seconds), is integrated with goma (for -google-internal users) for very high parallelism, and uses `sshfs` instead of -`scp` to significantly speed up the compile-run cycle. It has moved to https://sites.google.com/a/chromium.org/dev/developers/how-tos/-quickly-building-for-cros-arm-x64 -(mostly b/c of the ease of attaching files to sites). - ## Recipe2: Explicit Cross compiling @@ -40,13 +34,14 @@ ### Building To build for ARM, using the clang binary in the chrome tree, use the following -settings: +gn args: - export GYP_CROSSCOMPILE=1 - export GYP_DEFINES="target_arch=arm" + target_cpu = "arm" -There variables need to be set at gyp-time (when you run `gyp_chromium`), -but are not needed at build-time (when you run make/ninja). +Or the following gyp settings: + + GYP_CROSSCOMPILE=1 + GYP_DEFINES="target_arch=arm" ## Testing
diff --git a/docs/updating_clang.md b/docs/updating_clang.md index d8a8575..02dce25c 100644 --- a/docs/updating_clang.md +++ b/docs/updating_clang.md
@@ -2,7 +2,7 @@ 1. Sync your Chromium tree to the latest revision to pick up any plugin changes and test the new compiler against ToT -1. Update clang revision in tools/clang/scripts/update.sh, upload CL to +1. Update clang revision in tools/clang/scripts/update.py, upload CL to rietveld 1. Run tools/clang/scripts/package.py to create a tgz of the binary (mac and linux)
diff --git a/google_apis/gcm/base/mcs_util_unittest.cc b/google_apis/gcm/base/mcs_util_unittest.cc index d51f5a07..34d482d1 100644 --- a/google_apis/gcm/base/mcs_util_unittest.cc +++ b/google_apis/gcm/base/mcs_util_unittest.cc
@@ -31,12 +31,12 @@ // Test building a protobuf and extracting the tag from a protobuf. TEST(MCSUtilTest, ProtobufToTag) { - for (size_t i = 0; i < kNumProtoTypes; ++i) { + for (uint8 i = 0; i < kNumProtoTypes; ++i) { scoped_ptr<google::protobuf::MessageLite> protobuf = BuildProtobufFromTag(i); if (!protobuf.get()) // Not all tags have protobuf definitions. continue; - ASSERT_EQ((int)i, GetMCSProtoTag(*protobuf)) << "Type " << i; + ASSERT_EQ(i, GetMCSProtoTag(*protobuf)) << "Type " << i; } }
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index 64147b4..f3c787f6 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h
@@ -653,8 +653,10 @@ #ifndef GL_CHROMIUM_resize #define GL_CHROMIUM_resize 1 #ifdef GL_GLEXT_PROTOTYPES -GL_APICALL void GL_APIENTRY glResizeCHROMIUM( - GLuint width, GLuint height, GLfloat scale_factor); +GL_APICALL void GL_APIENTRY glResizeCHROMIUM(GLuint width, + GLuint height, + GLfloat scale_factor, + GLboolean alpha); #endif typedef void (GL_APIENTRYP PFNGLRESIZECHROMIUMPROC) ( GLuint width, GLuint height);
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc index 0ef42a23..a3fc0ed 100644 --- a/gpu/blink/webgraphicscontext3d_impl.cc +++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -223,7 +223,11 @@ return true; } -DELEGATE_TO_GL_3(reshapeWithScaleFactor, ResizeCHROMIUM, int, int, float) +void WebGraphicsContext3DImpl::reshapeWithScaleFactor(int width, + int height, + float scale) { + gl_->ResizeCHROMIUM(width, height, scale, true); +} DELEGATE_TO_GL_4R(mapBufferSubDataCHROMIUM, MapBufferSubDataCHROMIUM, WGC3Denum, WGC3Dintptr, WGC3Dsizeiptr, WGC3Denum, void*)
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 7003cbc..b274a6b 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1260,8 +1260,9 @@ } void GL_APIENTRY GLES2ResizeCHROMIUM(GLuint width, GLuint height, - GLfloat scale_factor) { - gles2::GetGLContext()->ResizeCHROMIUM(width, height, scale_factor); + GLfloat scale_factor, + GLboolean alpha) { + gles2::GetGLContext()->ResizeCHROMIUM(width, height, scale_factor, alpha); } const GLchar* GL_APIENTRY GLES2GetRequestableExtensionsCHROMIUM() { return gles2::GetGLContext()->GetRequestableExtensionsCHROMIUM();
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index e2123f5..b5cf24cd 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -2410,10 +2410,13 @@ } } -void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) { +void ResizeCHROMIUM(GLuint width, + GLuint height, + GLfloat scale_factor, + GLboolean alpha) { gles2::cmds::ResizeCHROMIUM* c = GetCmdSpace<gles2::cmds::ResizeCHROMIUM>(); if (c) { - c->Init(width, height, scale_factor); + c->Init(width, height, scale_factor, alpha); } }
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 208a08b..9b52768 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -4692,12 +4692,14 @@ CheckGLError(); } -void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height, - float scale_factor) { +void GLES2Implementation::ResizeCHROMIUM(GLuint width, + GLuint height, + float scale_factor, + GLboolean alpha) { GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM(" - << width << ", " << height << ", " << scale_factor << ")"); - helper_->ResizeCHROMIUM(width, height, scale_factor); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM(" << width << ", " + << height << ", " << scale_factor << ", " << alpha << ")"); + helper_->ResizeCHROMIUM(width, height, scale_factor, alpha); CheckGLError(); }
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index fc99066..0a4f886 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -870,7 +870,10 @@ void UnmapTexSubImage2DCHROMIUM(const void* mem) override; -void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) override; +void ResizeCHROMIUM(GLuint width, + GLuint height, + GLfloat scale_factor, + GLboolean alpha) override; const GLchar* GetRequestableExtensionsCHROMIUM() override;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index 23f6541..e8efce0 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -2792,9 +2792,9 @@ cmds::ResizeCHROMIUM cmd; }; Cmds expected; - expected.cmd.Init(1, 2, 3); + expected.cmd.Init(1, 2, 3, true); - gl_->ResizeCHROMIUM(1, 2, 3); + gl_->ResizeCHROMIUM(1, 2, 3, true); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); }
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 9edbc49..77872e7a 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -646,7 +646,8 @@ virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) = 0; virtual void ResizeCHROMIUM(GLuint width, GLuint height, - GLfloat scale_factor) = 0; + GLfloat scale_factor, + GLboolean alpha) = 0; virtual const GLchar* GetRequestableExtensionsCHROMIUM() = 0; virtual void RequestExtensionCHROMIUM(const char* extension) = 0; virtual void GetProgramInfoCHROMIUM(GLuint program,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index bc478cb..5469525 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -623,7 +623,10 @@ GLenum type, GLenum access) override; void UnmapTexSubImage2DCHROMIUM(const void* mem) override; -void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) override; +void ResizeCHROMIUM(GLuint width, + GLuint height, + GLfloat scale_factor, + GLboolean alpha) override; const GLchar* GetRequestableExtensionsCHROMIUM() override; void RequestExtensionCHROMIUM(const char* extension) override; void GetProgramInfoCHROMIUM(GLuint program,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index 4e3a7127..867652f 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -860,7 +860,8 @@ void GLES2InterfaceStub::UnmapTexSubImage2DCHROMIUM(const void* /* mem */) {} void GLES2InterfaceStub::ResizeCHROMIUM(GLuint /* width */, GLuint /* height */, - GLfloat /* scale_factor */) {} + GLfloat /* scale_factor */, + GLboolean /* alpha */) {} const GLchar* GLES2InterfaceStub::GetRequestableExtensionsCHROMIUM() { return 0; }
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 27923ea..209215e 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -623,7 +623,10 @@ GLenum type, GLenum access) override; void UnmapTexSubImage2DCHROMIUM(const void* mem) override; -void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) override; +void ResizeCHROMIUM(GLuint width, + GLuint height, + GLfloat scale_factor, + GLboolean alpha) override; const GLchar* GetRequestableExtensionsCHROMIUM() override; void RequestExtensionCHROMIUM(const char* extension) override; void GetProgramInfoCHROMIUM(GLuint program,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 1fc343f..77c6ab6 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1837,9 +1837,10 @@ void GLES2TraceImplementation::ResizeCHROMIUM(GLuint width, GLuint height, - GLfloat scale_factor) { + GLfloat scale_factor, + GLboolean alpha) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ResizeCHROMIUM"); - gl_->ResizeCHROMIUM(width, height, scale_factor); + gl_->ResizeCHROMIUM(width, height, scale_factor, alpha); } const GLchar* GLES2TraceImplementation::GetRequestableExtensionsCHROMIUM() {
diff --git a/gpu/command_buffer/client/query_tracker.cc b/gpu/command_buffer/client/query_tracker.cc index ec678a26..f5363f0 100644 --- a/gpu/command_buffer/client/query_tracker.cc +++ b/gpu/command_buffer/client/query_tracker.cc
@@ -67,7 +67,7 @@ buckets_.push_back(bucket); } - unsigned short index_in_bucket = 0; + size_t index_in_bucket = 0; for (size_t i = 0; i < kSyncsPerBucket; i++) { if (!bucket->in_use_queries[i]) { index_in_bucket = i;
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index fe6e9e9..42ed5f5e 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -265,7 +265,7 @@ GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenumBufferTarget target); GL_APICALL void* GL_APIENTRY glMapTexSubImage2DCHROMIUM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum access); GL_APICALL void GL_APIENTRY glUnmapTexSubImage2DCHROMIUM (const void* mem); -GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height, GLfloat scale_factor); +GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height, GLfloat scale_factor, GLboolean alpha); GL_APICALL const GLchar* GL_APIENTRY glGetRequestableExtensionsCHROMIUM (void); GL_APICALL void GL_APIENTRY glRequestExtensionCHROMIUM (const char* extension); GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index 95bf3a82..b26cea0 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -11899,15 +11899,23 @@ void SetHeader() { header.SetCmd<ValueType>(); } - void Init(GLuint _width, GLuint _height, GLfloat _scale_factor) { + void Init(GLuint _width, + GLuint _height, + GLfloat _scale_factor, + GLboolean _alpha) { SetHeader(); width = _width; height = _height; scale_factor = _scale_factor; + alpha = _alpha; } - void* Set(void* cmd, GLuint _width, GLuint _height, GLfloat _scale_factor) { - static_cast<ValueType*>(cmd)->Init(_width, _height, _scale_factor); + void* Set(void* cmd, + GLuint _width, + GLuint _height, + GLfloat _scale_factor, + GLboolean _alpha) { + static_cast<ValueType*>(cmd)->Init(_width, _height, _scale_factor, _alpha); return NextCmdAddress<ValueType>(cmd); } @@ -11915,10 +11923,11 @@ uint32_t width; uint32_t height; float scale_factor; + uint32_t alpha; }; -static_assert(sizeof(ResizeCHROMIUM) == 16, - "size of ResizeCHROMIUM should be 16"); +static_assert(sizeof(ResizeCHROMIUM) == 20, + "size of ResizeCHROMIUM should be 20"); static_assert(offsetof(ResizeCHROMIUM, header) == 0, "offset of ResizeCHROMIUM header should be 0"); static_assert(offsetof(ResizeCHROMIUM, width) == 4, @@ -11927,6 +11936,8 @@ "offset of ResizeCHROMIUM height should be 8"); static_assert(offsetof(ResizeCHROMIUM, scale_factor) == 12, "offset of ResizeCHROMIUM scale_factor should be 12"); +static_assert(offsetof(ResizeCHROMIUM, alpha) == 16, + "offset of ResizeCHROMIUM alpha should be 16"); struct GetRequestableExtensionsCHROMIUM { typedef GetRequestableExtensionsCHROMIUM ValueType;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index b165447..95a8ab8 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -4007,14 +4007,16 @@ TEST_F(GLES2FormatTest, ResizeCHROMIUM) { cmds::ResizeCHROMIUM& cmd = *GetBufferAs<cmds::ResizeCHROMIUM>(); - void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), - static_cast<GLuint>(12), static_cast<GLfloat>(13)); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12), + static_cast<GLfloat>(13), static_cast<GLboolean>(14)); EXPECT_EQ(static_cast<uint32_t>(cmds::ResizeCHROMIUM::kCmdId), cmd.header.command); EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); EXPECT_EQ(static_cast<GLuint>(11), cmd.width); EXPECT_EQ(static_cast<GLuint>(12), cmd.height); EXPECT_EQ(static_cast<GLfloat>(13), cmd.scale_factor); + EXPECT_EQ(static_cast<GLboolean>(14), cmd.alpha); CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index b2f7f969..34ddc02 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -12839,6 +12839,13 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); + + if (!source_texture_ref || !dest_texture_ref) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", + "unknown texture ids"); + return; + } + Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); int source_width = 0; @@ -12997,6 +13004,13 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); + + if (!source_texture_ref || !dest_texture_ref) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", + "unknown texture ids"); + return; + } + Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); int source_width = 0; @@ -13143,6 +13157,13 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); + + if (!source_texture_ref || !dest_texture_ref) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopyTextureCHROMIUM", + "unknown texture ids"); + return; + } + Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); int source_width = 0; @@ -13319,6 +13340,13 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); + + if (!source_texture_ref || !dest_texture_ref) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", + "unknown texture ids"); + return; + } + Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); int source_width = 0;
diff --git a/gpu/command_buffer/tests/es3_misc_functions_unittest.cc b/gpu/command_buffer/tests/es3_misc_functions_unittest.cc index 7f9769c..6b3ffa96 100644 --- a/gpu/command_buffer/tests/es3_misc_functions_unittest.cc +++ b/gpu/command_buffer/tests/es3_misc_functions_unittest.cc
@@ -32,7 +32,14 @@ GLManager gl_; }; -TEST_F(OpenGLES3FunctionTest, GetFragDataLocationInvalid) { +#if defined(OS_ANDROID) +// Test is failing for Lollipop 64 bit Tester. +// See crbug/550292. +#define MAYBE_GetFragDataLocationInvalid DISABLED_GetFragDataLocationInvalid +#else +#define MAYBE_GetFragDataLocationInvalid GetFragDataLocationInvalid +#endif +TEST_F(OpenGLES3FunctionTest, MAYBE_GetFragDataLocationInvalid) { if (!IsApplicable()) { return; }
diff --git a/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc index d50189d..e692b7d 100644 --- a/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc
@@ -310,6 +310,65 @@ EXPECT_TRUE(GL_INVALID_OPERATION == glGetError()); } +TEST_P(GLCompressedCopyTextureCHROMIUMTest, InvalidTextureIds) { + if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { + LOG(INFO) + << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; + return; + } + + CopyType copy_type = GetParam(); + + glBindTexture(GL_TEXTURE_2D, textures_[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, + 4, 0, sizeof(kCompressedImageDXT1), + kCompressedImageDXT1); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); + + glBindTexture(GL_TEXTURE_2D, textures_[1]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (copy_type == TexImage) { + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1]); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); + } else { + glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, + 4, 0, sizeof(kInvalidCompressedImage), + kInvalidCompressedImage); + + glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, 0, 0, + 0, 0, 4, 4); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], 0, 0, + 0, 0, 4, 4); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, 0, 0, 0, 0, + 4, 4); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + + glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], + textures_[1], 0, 0, 0, 0, 4, 4); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); + } +} + // Validate that some basic GL state is not touched upon execution of // the extension. TEST_P(GLCompressedCopyTextureCHROMIUMTest, BasicStatePreservation) {
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index a256fff8..7fdd252 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -639,6 +639,58 @@ EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); } +TEST_F(GLCopyTextureCHROMIUMTest, CopyTextureInvalidTextureIds) { + glBindTexture(GL_TEXTURE_2D, textures_[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + + glBindTexture(GL_TEXTURE_2D, textures_[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + + glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, GL_RGBA, + GL_UNSIGNED_BYTE, false, false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], GL_RGBA, + GL_UNSIGNED_BYTE, false, false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, GL_RGBA, GL_UNSIGNED_BYTE, + false, false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + GL_UNSIGNED_BYTE, false, false, false); + EXPECT_TRUE(GL_NO_ERROR == glGetError()); +} + +TEST_F(GLCopyTextureCHROMIUMTest, CopySubTextureInvalidTextureIds) { + glBindTexture(GL_TEXTURE_2D, textures_[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + + glBindTexture(GL_TEXTURE_2D, textures_[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + + glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, 1, 1, 0, 0, 1, 1, + false, false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], 1, 1, 0, 0, 1, 1, + false, false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, 1, 1, 0, 0, 1, 1, false, + false, false); + EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); + + glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, + 0, 1, 1, false, false, false); + EXPECT_TRUE(GL_NO_ERROR == glGetError()); +} + TEST_F(GLCopyTextureCHROMIUMTest, CopySubTextureOffset) { uint8 rgba_pixels[4 * 4] = {255u, 0u,
diff --git a/gpu/command_buffer/tests/gl_ext_srgb_unittest.cc b/gpu/command_buffer/tests/gl_ext_srgb_unittest.cc index 53b3c24f..5e709b8 100644 --- a/gpu/command_buffer/tests/gl_ext_srgb_unittest.cc +++ b/gpu/command_buffer/tests/gl_ext_srgb_unittest.cc
@@ -25,7 +25,14 @@ // Test to ensure that GL_SRGB_ALPHA as glTex(Sub)Image2D parameter works. This // is tricky because GL_SRGB_ALPHA is valid in OpenGL ES 2.0 but not valid in // OpenGL. -TEST_F(GLEXTSRGBTest, TexImageSRGBALPHAFormat) { +#if defined(OS_ANDROID) +// Test is failing for Lollipop 64 bit Tester. +// See crbug/550292. +#define MAYBE_TexImageSRGBALPHAFormat DISABLED_TexImageSRGBALPHAFormat +#else +#define MAYBE_TexImageSRGBALPHAFormat TexImageSRGBALPHAFormat +#endif +TEST_F(GLEXTSRGBTest, MAYBE_TexImageSRGBALPHAFormat) { if (!IsApplicable()) return; static const int kWidth = 10;
diff --git a/gpu/command_buffer/tests/gl_texture_mailbox_unittest.cc b/gpu/command_buffer/tests/gl_texture_mailbox_unittest.cc index 3ceb5ff6..6025427 100644 --- a/gpu/command_buffer/tests/gl_texture_mailbox_unittest.cc +++ b/gpu/command_buffer/tests/gl_texture_mailbox_unittest.cc
@@ -341,7 +341,7 @@ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); gl2_.MakeCurrent(); - glResizeCHROMIUM(10, 10, 1); + glResizeCHROMIUM(10, 10, 1, true); glClearColor(1, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); ::gles2::GetGLContext()->SwapBuffers(); @@ -430,7 +430,7 @@ for (size_t i = 0; i < 2; ++i) { other_gl[i].MakeCurrent(); - glResizeCHROMIUM(10, 10, 1); + glResizeCHROMIUM(10, 10, 1, true); glClearColor(1-i%2, i%2, 0, 1); glClear(GL_COLOR_BUFFER_BIT); ::gles2::GetGLContext()->SwapBuffers();
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h index b0972229..a262864 100644 --- a/ios/chrome/browser/experimental_flags.h +++ b/ios/chrome/browser/experimental_flags.h
@@ -5,6 +5,8 @@ #ifndef IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_ #define IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_ +#include <string> + // This file can be empty. Its purpose is to contain the relatively short lived // declarations required for experimental flags. @@ -30,6 +32,10 @@ // The returned value will not change within a given session. bool IsWKWebViewEnabled(); +// Returns a string containing extra params that should be sent along with +// omnibox search requests. The returned value contains a leading "&". +std::string GetWKWebViewSearchParams(); + // Whether keyboard commands are supported. bool AreKeyboardCommandsEnabled();
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index 8dcf78ec..3b31adf 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -7,6 +7,7 @@ #include "ios/chrome/browser/experimental_flags.h" +#include <dispatch/dispatch.h> #import <Foundation/Foundation.h> #include <string> @@ -74,31 +75,64 @@ base::CompareCase::INSENSITIVE_ASCII); } +// Helper method that returns true if it is safe to check the finch group for +// the IOSUseWKWebView experiment. Some users are ineligible to be in the +// trial, so for those users, this method returns false. If this method returns +// false, do not check for the current finch group, as doing so will incorrectly +// mark the current user as being in the experiment. +bool CanCheckWKWebViewExperiment() { + // True if this user is eligible for the WKWebView experiment and it is ok to + // check the experiment group. + static bool ok_to_check_finch = false; + static dispatch_once_t once; + dispatch_once(&once, ^{ + // If g_wkwebview_trial_eligibility hasn't been set, default it to + // ineligible. This ensures future calls to try to set it will DCHECK. + if (g_wkwebview_trial_eligibility == WKWebViewEligibility::UNSET) { + g_wkwebview_trial_eligibility = WKWebViewEligibility::INELIGIBLE; + } + + // If WKWebView isn't supported, don't activate the experiment at all. This + // avoids someone being slotted into the WKWebView bucket (and thus + // reporting as WKWebView), but actually running UIWebView. + if (!web::IsWKWebViewSupported()) { + ok_to_check_finch = false; + return; + } + + // Check for a flag forcing a specific group. Even ineligible users can be + // opted into WKWebView if an override flag is set. + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + bool trial_overridden = + command_line->HasSwitch(switches::kEnableIOSWKWebView) || + command_line->HasSwitch(switches::kDisableIOSWKWebView); + + // If the user isn't eligible for the trial (i.e., their state is such that + // they should not be automatically selected for the group), and there's no + // explicit override, don't check the group (again, to avoid having them + // report as part of a group at all). + if (g_wkwebview_trial_eligibility == WKWebViewEligibility::INELIGIBLE && + !trial_overridden) { + ok_to_check_finch = false; + return; + } + + ok_to_check_finch = true; + }); + + return ok_to_check_finch; +} + bool IsWKWebViewEnabled() { - // If g_wkwebview_trial_eligibility hasn't been set, default it to - // ineligibile. This ensures future calls to try to set it will DCHECK. - if (g_wkwebview_trial_eligibility == WKWebViewEligibility::UNSET) { - g_wkwebview_trial_eligibility = WKWebViewEligibility::INELIGIBLE; + if (!CanCheckWKWebViewExperiment()) { + return false; } - // If WKWebView isn't supported, don't activate the experiment at all. This - // avoids someone being slotted into the WKWebView bucket (and thus reporting - // as WKWebView), but actually running UIWebView. - if (!web::IsWKWebViewSupported()) - return false; - - // Check for a flag forcing a specific group. + // Check if the experimental flag is turned on. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - bool force_enable = command_line->HasSwitch(switches::kEnableIOSWKWebView); - bool force_disable = command_line->HasSwitch(switches::kDisableIOSWKWebView); - bool trial_overridden = force_enable || force_disable; - - // If the user isn't eligible for the trial (i.e., their state is such that - // they should not be automatically selected for the group), and there's no - // explicit override, don't check the group (again, to avoid having them - // report as part of a group at all). - if (g_wkwebview_trial_eligibility == WKWebViewEligibility::INELIGIBLE && - !trial_overridden) + if (command_line->HasSwitch(switches::kEnableIOSWKWebView)) + return true; + else if (command_line->HasSwitch(switches::kDisableIOSWKWebView)) return false; // Now that it's been established that user is a candidate, set up the trial @@ -106,17 +140,19 @@ std::string group_name = base::FieldTrialList::FindFullName("IOSUseWKWebView"); - // Check if the experimental flag is turned on. - if (force_enable) - return true; - else if (force_disable) - return false; - // Check if the finch experiment is turned on. return base::StartsWith(group_name, "Enabled", base::CompareCase::INSENSITIVE_ASCII); } +std::string GetWKWebViewSearchParams() { + if (!CanCheckWKWebViewExperiment()) { + return std::string(); + } + + return variations::GetVariationParamValue("IOSUseWKWebView", "esrch"); +} + bool AreKeyboardCommandsEnabled() { return !base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableKeyboardCommands);
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc index e09d36f..d6e92f6 100644 --- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc +++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -12,10 +12,12 @@ #include "components/search/search.h" #include "components/version_info/version_info.h" #include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/experimental_flags.h" #include "ios/chrome/browser/google/google_brand.h" #include "ios/chrome/browser/google/google_url_tracker_factory.h" #include "ios/chrome/common/channel_info.h" #include "ios/web/public/web_thread.h" +#include "net/base/escape.h" #include "url/gurl.h" #if defined(ENABLE_RLZ) @@ -119,6 +121,16 @@ return std::string(); } +std::string UIThreadSearchTermsData::IOSWebViewTypeParam() const { + DCHECK(thread_checker_.CalledOnValidThread()); + std::string param = experimental_flags::GetWKWebViewSearchParams(); + if (param.empty()) { + return std::string(); + } + + return "&esrch=" + net::EscapeQueryParamValue(param, true); +} + std::string UIThreadSearchTermsData::GoogleImageSearchSource() const { DCHECK(thread_checker_.CalledOnValidThread()); std::string version(version_info::GetProductName() + " " +
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h index 7e7e01be..0c8a2c2 100644 --- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h +++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -31,6 +31,7 @@ std::string ForceInstantResultsParam(bool for_prerender) const override; int OmniboxStartMargin() const override; std::string NTPIsThemedParam() const override; + std::string IOSWebViewTypeParam() const override; std::string GoogleImageSearchSource() const override; private:
diff --git a/ios/crnet/crnet_environment.mm b/ios/crnet/crnet_environment.mm index e281a7f..6dcf9f3 100644 --- a/ios/crnet/crnet_environment.mm +++ b/ios/crnet/crnet_environment.mm
@@ -428,7 +428,6 @@ params.channel_id_service = main_context_->channel_id_service(); params.transport_security_state = main_context_->transport_security_state(); params.proxy_service = main_context_->proxy_service(); - params.ssl_session_cache_shard = ""; params.ssl_config_service = main_context_->ssl_config_service(); params.http_auth_handler_factory = main_context_->http_auth_handler_factory(); params.network_delegate = main_context_->network_delegate();
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc index 1f73e781..3023c05e 100644 --- a/ipc/ipc_channel_posix.cc +++ b/ipc/ipc_channel_posix.cc
@@ -24,6 +24,7 @@ #include <algorithm> #include <map> #include <string> +#include <utility> #include "base/command_line.h" #include "base/files/file_path.h" @@ -544,7 +545,7 @@ if (!client_pipe_.is_valid()) return base::ScopedFD(); PipeMap::GetInstance()->Remove(pipe_name_); - return client_pipe_.Pass(); + return std::move(client_pipe_); } void ChannelPosix::CloseClientFileDescriptor() {
diff --git a/ipc/ipc_platform_file_attachment_posix.cc b/ipc/ipc_platform_file_attachment_posix.cc index b704750c1..b130ab2 100644 --- a/ipc/ipc_platform_file_attachment_posix.cc +++ b/ipc/ipc_platform_file_attachment_posix.cc
@@ -4,6 +4,8 @@ #include "ipc/ipc_platform_file_attachment_posix.h" +#include <utility> + namespace IPC { namespace internal { @@ -12,8 +14,7 @@ } PlatformFileAttachment::PlatformFileAttachment(base::ScopedFD file) - : file_(file.get()), owning_(file.Pass()) { -} + : file_(file.get()), owning_(std::move(file)) {} PlatformFileAttachment::~PlatformFileAttachment() { }
diff --git a/mandoline/ui/desktop_ui/browser_window.cc b/mandoline/ui/desktop_ui/browser_window.cc index 6100a57..c0bda9e 100644 --- a/mandoline/ui/desktop_ui/browser_window.cc +++ b/mandoline/ui/desktop_ui/browser_window.cc
@@ -208,27 +208,31 @@ host_->AddAccelerator( static_cast<uint32_t>(BrowserCommand::CLOSE), mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_W, - mus::mojom::EVENT_FLAGS_CONTROL_DOWN)); + mus::mojom::EVENT_FLAGS_CONTROL_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); host_->AddAccelerator( static_cast<uint32_t>(BrowserCommand::FOCUS_OMNIBOX), mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_L, - mus::mojom::EVENT_FLAGS_CONTROL_DOWN)); + mus::mojom::EVENT_FLAGS_CONTROL_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); host_->AddAccelerator( static_cast<uint32_t>(BrowserCommand::NEW_WINDOW), mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_N, - mus::mojom::EVENT_FLAGS_CONTROL_DOWN)); + mus::mojom::EVENT_FLAGS_CONTROL_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); host_->AddAccelerator( static_cast<uint32_t>(BrowserCommand::SHOW_FIND), mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_F, - mus::mojom::EVENT_FLAGS_CONTROL_DOWN)); - host_->AddAccelerator( - static_cast<uint32_t>(BrowserCommand::GO_BACK), - mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_LEFT, - mus::mojom::EVENT_FLAGS_ALT_DOWN)); - host_->AddAccelerator( - static_cast<uint32_t>(BrowserCommand::GO_FORWARD), - mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_RIGHT, - mus::mojom::EVENT_FLAGS_ALT_DOWN)); + mus::mojom::EVENT_FLAGS_CONTROL_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); + host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::GO_BACK), + mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_LEFT, + mus::mojom::EVENT_FLAGS_ALT_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); + host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::GO_FORWARD), + mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_RIGHT, + mus::mojom::EVENT_FLAGS_ALT_DOWN), + mus::mojom::WindowTreeHost::AddAcceleratorCallback()); // Now that we're ready, load the default url. LoadURL(default_url_);
diff --git a/mash/wm/BUILD.gn b/mash/wm/BUILD.gn index 4812458..743307d 100644 --- a/mash/wm/BUILD.gn +++ b/mash/wm/BUILD.gn
@@ -16,6 +16,8 @@ source_set("lib") { sources = [ + "accelerator_registrar_impl.cc", + "accelerator_registrar_impl.h", "background_layout.cc", "background_layout.h", "frame/caption_buttons/caption_button_types.h",
diff --git a/mash/wm/accelerator_registrar_impl.cc b/mash/wm/accelerator_registrar_impl.cc new file mode 100644 index 0000000..73b2237 --- /dev/null +++ b/mash/wm/accelerator_registrar_impl.cc
@@ -0,0 +1,110 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mash/wm/accelerator_registrar_impl.h" + +#include "base/bind.h" +#include "components/mus/public/interfaces/window_tree_host.mojom.h" + +namespace mash { +namespace wm { + +namespace { +const int kAcceleratorIdMask = 0xffff; +} + +AcceleratorRegistrarImpl::AcceleratorRegistrarImpl( + mus::mojom::WindowTreeHost* host, + uint32_t accelerator_namespace, + mojo::InterfaceRequest<AcceleratorRegistrar> request, + const DestroyCallback& destroy_callback) + : host_(host), + binding_(this, request.Pass()), + accelerator_namespace_(accelerator_namespace & 0xffff), + destroy_callback_(destroy_callback) { + binding_.set_connection_error_handler(base::Bind( + &AcceleratorRegistrarImpl::OnBindingGone, base::Unretained(this))); +} + +AcceleratorRegistrarImpl::~AcceleratorRegistrarImpl() { + for (uint32_t accelerator_id : accelerator_ids_) + host_->RemoveAccelerator(accelerator_id); + destroy_callback_.Run(this); +} + +bool AcceleratorRegistrarImpl::OwnsAccelerator(uint32_t accelerator_id) const { + return !!accelerator_ids_.count(accelerator_id); +} + +void AcceleratorRegistrarImpl::ProcessAccelerator(uint32_t accelerator_id, + mus::mojom::EventPtr event) { + DCHECK(OwnsAccelerator(accelerator_id)); + accelerator_handler_->OnAccelerator(accelerator_id & kAcceleratorIdMask, + event.Pass()); +} + +uint32_t AcceleratorRegistrarImpl::ComputeAcceleratorId( + uint32_t accelerator_id) const { + return (accelerator_namespace_ << 16) | (accelerator_id & kAcceleratorIdMask); +} + +void AcceleratorRegistrarImpl::OnBindingGone() { + binding_.Unbind(); + // If there's no outstanding accelerators for this connection, then destroy + // it. + if (accelerator_ids_.empty()) + delete this; +} + +void AcceleratorRegistrarImpl::OnHandlerGone() { + // The handler is dead. If AcceleratorRegistrar connection is also closed, + // then destroy this. Otherwise, remove all the accelerators, but keep the + // AcceleratorRegistrar connection alive (the client could still set another + // handler and install new accelerators). + if (!binding_.is_bound()) { + delete this; + return; + } + accelerator_handler_.reset(); + for (uint32_t accelerator_id : accelerator_ids_) + host_->RemoveAccelerator(accelerator_id); +} + +void AcceleratorRegistrarImpl::SetHandler( + mus::mojom::AcceleratorHandlerPtr handler) { + accelerator_handler_ = handler.Pass(); + accelerator_handler_.set_connection_error_handler(base::Bind( + &AcceleratorRegistrarImpl::OnHandlerGone, base::Unretained(this))); +} + +void AcceleratorRegistrarImpl::AddAccelerator( + uint32_t accelerator_id, + mus::mojom::EventMatcherPtr matcher, + const AddAcceleratorCallback& callback) { + if (!accelerator_handler_ || + (accelerator_id & kAcceleratorIdMask) != accelerator_id) { + // The |accelerator_id| is too large, and it can't be handled correctly. + callback.Run(false); + return; + } + uint32_t namespaced_accelerator_id = ComputeAcceleratorId(accelerator_id); + accelerator_ids_.insert(namespaced_accelerator_id); + host_->AddAccelerator(namespaced_accelerator_id, matcher.Pass(), callback); +} + +void AcceleratorRegistrarImpl::RemoveAccelerator(uint32_t accelerator_id) { + uint32_t namespaced_accelerator_id = ComputeAcceleratorId(accelerator_id); + if (!accelerator_ids_.count(namespaced_accelerator_id)) + return; + host_->RemoveAccelerator(namespaced_accelerator_id); + accelerator_ids_.erase(namespaced_accelerator_id); + // If the registrar is not bound anymore (i.e. the client can no longer + // install new accelerators), and the last accelerator has been removed, then + // there's no point keeping this alive anymore. + if (accelerator_ids_.empty() && !binding_.is_bound()) + delete this; +} + +} // namespace wm +} // namespace mash
diff --git a/mash/wm/accelerator_registrar_impl.h b/mash/wm/accelerator_registrar_impl.h new file mode 100644 index 0000000..8d5fda61 --- /dev/null +++ b/mash/wm/accelerator_registrar_impl.h
@@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MASH_WM_ACCELERATOR_REGISTRAR_IMPL_H_ +#define MASH_WM_ACCELERATOR_REGISTRAR_IMPL_H_ + +#include <set> + +#include "base/callback.h" +#include "base/macros.h" +#include "components/mus/public/interfaces/accelerator_registrar.mojom.h" +#include "mojo/common/weak_binding_set.h" +#include "mojo/public/cpp/bindings/strong_binding.h" + +namespace mus { +namespace mojom { +class WindowTreeHost; +} +} + +namespace mash { +namespace wm { + +class WindowManagerApplication; + +// Manages AcceleratorHandlers from a particular AcceleratorRegistrar +// connection. This manages its own lifetime, and destroys itself when the +// AcceleratorRegistrar and all its AcceleratorHandlers are disconnected. Upon +// destruction, it calls the DestroyCallback. +class AcceleratorRegistrarImpl : public mus::mojom::AcceleratorRegistrar { + public: + using DestroyCallback = base::Callback<void(AcceleratorRegistrarImpl*)>; + AcceleratorRegistrarImpl(mus::mojom::WindowTreeHost* host, + uint32_t accelerator_namespace, + mojo::InterfaceRequest<AcceleratorRegistrar> request, + const DestroyCallback& destroy_callback); + + bool OwnsAccelerator(uint32_t accelerator_id) const; + void ProcessAccelerator(uint32_t accelerator_id, mus::mojom::EventPtr event); + + private: + ~AcceleratorRegistrarImpl() override; + + uint32_t ComputeAcceleratorId(uint32_t accelerator_id) const; + void OnBindingGone(); + void OnHandlerGone(); + + // mus::mojom::AcceleratorRegistrar: + void SetHandler(mus::mojom::AcceleratorHandlerPtr handler) override; + void AddAccelerator(uint32_t accelerator_id, + mus::mojom::EventMatcherPtr matcher, + const AddAcceleratorCallback& callback) override; + void RemoveAccelerator(uint32_t accelerator_id) override; + + mus::mojom::WindowTreeHost* host_; + mus::mojom::AcceleratorHandlerPtr accelerator_handler_; + mojo::Binding<AcceleratorRegistrar> binding_; + uint32_t accelerator_namespace_; + std::set<uint32_t> accelerator_ids_; + DestroyCallback destroy_callback_; + + DISALLOW_COPY_AND_ASSIGN(AcceleratorRegistrarImpl); +}; + +} // namespace wm +} // namespace mash + +#endif // MASH_WM_ACCELERATOR_REGISTRAR_IMPL_H_
diff --git a/mash/wm/frame/non_client_frame_view_mash.cc b/mash/wm/frame/non_client_frame_view_mash.cc index d1d85863..17af114e3 100644 --- a/mash/wm/frame/non_client_frame_view_mash.cc +++ b/mash/wm/frame/non_client_frame_view_mash.cc
@@ -176,6 +176,15 @@ return gfx::Insets(header_height, 0, 0, 0); } +// static +int NonClientFrameViewMash::GetMaxTitleBarButtonWidth() { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + return rb.GetImageSkiaNamed(IDR_MASH_WM_WINDOW_CONTROL_BACKGROUND_P) + ->size() + .width() * + 3; +} + void NonClientFrameViewMash::SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color) { header_view_->SetFrameColors(active_frame_color, inactive_frame_color);
diff --git a/mash/wm/frame/non_client_frame_view_mash.h b/mash/wm/frame/non_client_frame_view_mash.h index eb39bc2a..f87ef2e6 100644 --- a/mash/wm/frame/non_client_frame_view_mash.h +++ b/mash/wm/frame/non_client_frame_view_mash.h
@@ -39,6 +39,7 @@ ~NonClientFrameViewMash() override; static gfx::Insets GetPreferredClientAreaInsets(); + static int GetMaxTitleBarButtonWidth(); // Sets the active and inactive frame colors. Note the inactive frame color // will have some transparency added when the frame is drawn.
diff --git a/mash/wm/non_client_frame_controller.cc b/mash/wm/non_client_frame_controller.cc index 3900632..4cd4027 100644 --- a/mash/wm/non_client_frame_controller.cc +++ b/mash/wm/non_client_frame_controller.cc
@@ -174,6 +174,11 @@ return NonClientFrameViewMash::GetPreferredClientAreaInsets(); } +// static +int NonClientFrameController::GetMaxTitleBarButtonWidth() { + return NonClientFrameViewMash::GetMaxTitleBarButtonWidth(); +} + NonClientFrameController::~NonClientFrameController() { if (window_) window_->RemoveObserver(this);
diff --git a/mash/wm/non_client_frame_controller.h b/mash/wm/non_client_frame_controller.h index 492500d..e61d474d 100644 --- a/mash/wm/non_client_frame_controller.h +++ b/mash/wm/non_client_frame_controller.h
@@ -39,6 +39,10 @@ // Returns the preferred client area insets. static gfx::Insets GetPreferredClientAreaInsets(); + // Returns the width needed to display the standard set of buttons on the + // title bar. + static int GetMaxTitleBarButtonWidth(); + private: ~NonClientFrameController() override;
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc index 6d2aeb88..3a211d5 100644 --- a/mash/wm/window_manager_application.cc +++ b/mash/wm/window_manager_application.cc
@@ -4,11 +4,13 @@ #include "mash/wm/window_manager_application.h" +#include "base/bind.h" #include "components/mus/common/util.h" #include "components/mus/public/cpp/event_matcher.h" #include "components/mus/public/cpp/window.h" #include "components/mus/public/cpp/window_tree_connection.h" #include "components/mus/public/cpp/window_tree_host_factory.h" +#include "mash/wm/accelerator_registrar_impl.h" #include "mash/wm/background_layout.h" #include "mash/wm/shelf_layout.h" #include "mash/wm/window_layout.h" @@ -23,6 +25,11 @@ namespace wm { namespace { const uint32_t kWindowSwitchCmd = 1; + +void AssertTrue(bool success) { + DCHECK(success); +} + } // namespace WindowManagerApplication::WindowManagerApplication() @@ -53,7 +60,13 @@ window_tree_host_->AddAccelerator( kWindowSwitchCmd, mus::CreateKeyMatcher(mus::mojom::KEYBOARD_CODE_TAB, - mus::mojom::EVENT_FLAGS_CONTROL_DOWN)); + mus::mojom::EVENT_FLAGS_CONTROL_DOWN), + base::Bind(&AssertTrue)); +} + +void WindowManagerApplication::OnAcceleratorRegistrarDestroyed( + AcceleratorRegistrarImpl* registrar) { + accelerator_registrars_.erase(registrar); } void WindowManagerApplication::Initialize(mojo::ApplicationImpl* app) { @@ -73,7 +86,8 @@ bool WindowManagerApplication::ConfigureIncomingConnection( mojo::ApplicationConnection* connection) { - connection->AddService(this); + connection->AddService<mus::mojom::AcceleratorRegistrar>(this); + connection->AddService<mus::mojom::WindowManager>(this); return true; } @@ -84,7 +98,12 @@ window_tree_host_->ActivateNextWindow(); break; default: - NOTREACHED() << "Unknown accelerator command: " << id; + for (auto* registrar : accelerator_registrars_) { + if (registrar->OwnsAccelerator(id)) { + registrar->ProcessAccelerator(id, event.Pass()); + break; + } + } } } @@ -121,6 +140,24 @@ void WindowManagerApplication::Create( mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mus::mojom::AcceleratorRegistrar> request) { + static int accelerator_registrar_count = 0; + if (accelerator_registrar_count == std::numeric_limits<int>::max()) { + // Restart from zero if we have reached the limit. It is technically + // possible to end up with multiple active registrars with the same + // namespace, but it is highly unlikely. In the event that multiple + // registrars have the same namespace, this new registrar will be unable to + // install accelerators. + accelerator_registrar_count = 0; + } + accelerator_registrars_.insert(new AcceleratorRegistrarImpl( + window_tree_host_.get(), ++accelerator_registrar_count, request.Pass(), + base::Bind(&WindowManagerApplication::OnAcceleratorRegistrarDestroyed, + base::Unretained(this)))); +} + +void WindowManagerApplication::Create( + mojo::ApplicationConnection* connection, mojo::InterfaceRequest<mus::mojom::WindowManager> request) { if (root_) { window_manager_binding_.AddBinding(window_manager_.get(), request.Pass());
diff --git a/mash/wm/window_manager_application.h b/mash/wm/window_manager_application.h index e7c5a43..45916ea 100644 --- a/mash/wm/window_manager_application.h +++ b/mash/wm/window_manager_application.h
@@ -5,12 +5,15 @@ #ifndef MASH_WM_WINDOW_MANAGER_APPLICATION_H_ #define MASH_WM_WINDOW_MANAGER_APPLICATION_H_ +#include <set> + #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "components/mus/common/types.h" #include "components/mus/public/cpp/window_observer.h" #include "components/mus/public/cpp/window_tree_delegate.h" +#include "components/mus/public/interfaces/accelerator_registrar.mojom.h" #include "components/mus/public/interfaces/window_manager.mojom.h" #include "components/mus/public/interfaces/window_tree_host.mojom.h" #include "mash/wm/public/interfaces/container.mojom.h" @@ -32,6 +35,7 @@ namespace mash { namespace wm { +class AcceleratorRegistrarImpl; class BackgroundLayout; class ShelfLayout; class WindowLayout; @@ -42,7 +46,8 @@ public mus::WindowObserver, public mus::mojom::WindowTreeHostClient, public mus::WindowTreeDelegate, - public mojo::InterfaceFactory<mus::mojom::WindowManager> { + public mojo::InterfaceFactory<mus::mojom::WindowManager>, + public mojo::InterfaceFactory<mus::mojom::AcceleratorRegistrar> { public: WindowManagerApplication(); ~WindowManagerApplication() override; @@ -64,6 +69,7 @@ private: void AddAccelerators(); + void OnAcceleratorRegistrarDestroyed(AcceleratorRegistrarImpl* registrar); // ApplicationDelegate: void Initialize(mojo::ApplicationImpl* app) override; @@ -77,6 +83,11 @@ void OnEmbed(mus::Window* root) override; void OnConnectionLost(mus::WindowTreeConnection* connection) override; + // InterfaceFactory<mus::mojom::AcceleratorRegistrar>: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mus::mojom::AcceleratorRegistrar> request) + override; + // InterfaceFactory<mus::mojom::WindowManager>: void Create( mojo::ApplicationConnection* connection, @@ -112,6 +123,8 @@ scoped_ptr<ShelfLayout> shelf_layout_; scoped_ptr<WindowLayout> window_layout_; + std::set<AcceleratorRegistrarImpl*> accelerator_registrars_; + DISALLOW_COPY_AND_ASSIGN(WindowManagerApplication); };
diff --git a/mash/wm/window_manager_apptest.cc b/mash/wm/window_manager_apptest.cc index 079af7b..5e235fc 100644 --- a/mash/wm/window_manager_apptest.cc +++ b/mash/wm/window_manager_apptest.cc
@@ -46,8 +46,7 @@ DISALLOW_COPY_AND_ASSIGN(WindowManagerAppTest); }; -// TODO(sky): flakey, http://crbug.com/559412 . -TEST_F(WindowManagerAppTest, DISABLED_OpenWindow) { +TEST_F(WindowManagerAppTest, OpenWindow) { mus::mojom::WindowManagerPtr connection; ConnectToWindowManager(&connection);
diff --git a/mash/wm/window_manager_impl.cc b/mash/wm/window_manager_impl.cc index e5105c1..36caed72 100644 --- a/mash/wm/window_manager_impl.cc +++ b/mash/wm/window_manager_impl.cc
@@ -139,6 +139,9 @@ config->maximized_client_area_insets = mojo::Insets::From(client_area_insets); + config->max_title_bar_button_width = + NonClientFrameController::GetMaxTitleBarButtonWidth(); + callback.Run(config.Pass()); }
diff --git a/media/blink/buffered_resource_loader.cc b/media/blink/buffered_resource_loader.cc index ab3a5830..f742f89 100644 --- a/media/blink/buffered_resource_loader.cc +++ b/media/blink/buffered_resource_loader.cc
@@ -4,6 +4,10 @@ #include "media/blink/buffered_resource_loader.h" +#include <stdint.h> + +#include <limits> + #include "base/bits.h" #include "base/callback_helpers.h" #include "base/metrics/histogram.h" @@ -94,15 +98,14 @@ std::swap(*out_forward_capacity, *out_backward_capacity); } -BufferedResourceLoader::BufferedResourceLoader( - const GURL& url, - CORSMode cors_mode, - int64 first_byte_position, - int64 last_byte_position, - DeferStrategy strategy, - int bitrate, - double playback_rate, - MediaLog* media_log) +BufferedResourceLoader::BufferedResourceLoader(const GURL& url, + CORSMode cors_mode, + int64_t first_byte_position, + int64_t last_byte_position, + DeferStrategy strategy, + int bitrate, + double playback_rate, + MediaLog* media_log) : buffer_(kMinBufferCapacity, kMinBufferCapacity), loader_failed_(false), defer_strategy_(strategy), @@ -126,7 +129,6 @@ playback_rate_(playback_rate), media_log_(media_log), cancel_upon_deferral_(false) { - // Set the initial capacity of |buffer_| based on |bitrate_| and // |playback_rate_|. UpdateBufferWindow(); @@ -216,11 +218,10 @@ active_loader_.reset(); } -void BufferedResourceLoader::Read( - int64 position, - int read_size, - uint8* buffer, - const ReadCB& read_cb) { +void BufferedResourceLoader::Read(int64_t position, + int read_size, + uint8_t* buffer, + const ReadCB& read_cb) { DCHECK(start_cb_.is_null()); DCHECK(read_cb_.is_null()); DCHECK(!read_cb.is_null()); @@ -254,8 +255,8 @@ // Make sure |offset_| and |read_position_| does not differ by a large // amount. - if (read_position_ > offset_ + kint32max || - read_position_ < offset_ + kint32min) { + if (read_position_ > offset_ + std::numeric_limits<int32_t>::max() || + read_position_ < offset_ + std::numeric_limits<int32_t>::min()) { DoneRead(kCacheMiss, 0); return; } @@ -312,11 +313,11 @@ DoneRead(kCacheMiss, 0); } -int64 BufferedResourceLoader::content_length() { +int64_t BufferedResourceLoader::content_length() { return content_length_; } -int64 BufferedResourceLoader::instance_size() { +int64_t BufferedResourceLoader::instance_size() { return instance_size_; } @@ -379,7 +380,7 @@ if (start_cb_.is_null()) return; - uint32 reasons = GetReasonsForUncacheability(response); + uint32_t reasons = GetReasonsForUncacheability(response); might_be_reused_from_cache_in_future_ = reasons == 0; UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0); int shift = 0; @@ -468,7 +469,7 @@ DCHECK(active_loader_.get()); DCHECK_GT(data_length, 0); - buffer_.Append(reinterpret_cast<const uint8*>(data), data_length); + buffer_.Append(reinterpret_cast<const uint8_t*>(data), data_length); // If there is an active read request, try to fulfill the request. if (HasPendingRead() && CanFulfillRead()) @@ -715,14 +716,16 @@ DoneRead(kOk, read); } -int64 BufferedResourceLoader::first_byte_position() const { +int64_t BufferedResourceLoader::first_byte_position() const { return first_byte_position_; } // static bool BufferedResourceLoader::ParseContentRange( - const std::string& content_range_str, int64* first_byte_position, - int64* last_byte_position, int64* instance_size) { + const std::string& content_range_str, + int64_t* first_byte_position, + int64_t* last_byte_position, + int64_t* instance_size) { const std::string kUpThroughBytesUnit = "bytes "; if (content_range_str.find(kUpThroughBytesUnit) != 0) return false; @@ -772,7 +775,7 @@ bool BufferedResourceLoader::VerifyPartialResponse( const WebURLResponse& response) { - int64 first_byte_position, last_byte_position, instance_size; + int64_t first_byte_position, last_byte_position, instance_size; if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(), &first_byte_position, &last_byte_position, &instance_size)) {
diff --git a/media/blink/buffered_resource_loader.h b/media/blink/buffered_resource_loader.h index 598f075..f55569ed 100644 --- a/media/blink/buffered_resource_loader.h +++ b/media/blink/buffered_resource_loader.h
@@ -77,15 +77,14 @@ // |strategy| is the initial loading strategy to use. // |bitrate| is the bitrate of the media, 0 if unknown. // |playback_rate| is the current playback rate of the media. - BufferedResourceLoader( - const GURL& url, - CORSMode cors_mode, - int64 first_byte_position, - int64 last_byte_position, - DeferStrategy strategy, - int bitrate, - double playback_rate, - MediaLog* media_log); + BufferedResourceLoader(const GURL& url, + CORSMode cors_mode, + int64_t first_byte_position, + int64_t last_byte_position, + DeferStrategy strategy, + int bitrate, + double playback_rate, + MediaLog* media_log); ~BufferedResourceLoader() override; // Start the resource loading with the specified URL and range. @@ -94,7 +93,7 @@ // |progress_cb| is executed when additional data has arrived. typedef base::Callback<void(Status)> StartCB; typedef base::Callback<void(LoadingState)> LoadingStateChangedCB; - typedef base::Callback<void(int64)> ProgressCB; + typedef base::Callback<void(int64_t)> ProgressCB; void Start(const StartCB& start_cb, const LoadingStateChangedCB& loading_cb, const ProgressCB& progress_cb, @@ -115,17 +114,19 @@ // If necessary will temporarily increase forward capacity of buffer to // accomodate an unusually large read. typedef base::Callback<void(Status, int)> ReadCB; - void Read(int64 position, int read_size, - uint8* buffer, const ReadCB& read_cb); + void Read(int64_t position, + int read_size, + uint8_t* buffer, + const ReadCB& read_cb); // Gets the content length in bytes of the instance after this loader has been // started. If this value is |kPositionNotSpecified|, then content length is // unknown. - int64 content_length(); + int64_t content_length(); // Gets the original size of the file requested. If this value is // |kPositionNotSpecified|, then the size is unknown. - int64 instance_size(); + int64_t instance_size(); // Returns true if the server supports byte range requests. bool range_supported(); @@ -154,10 +155,9 @@ void didReceiveCachedMetadata( blink::WebURLLoader* loader, const char* data, int dataLength) override; - void didFinishLoading( - blink::WebURLLoader* loader, - double finishTime, - int64_t total_encoded_data_length) override; + void didFinishLoading(blink::WebURLLoader* loader, + double finishTime, + int64_t total_encoded_data_length) override; void didFail( blink::WebURLLoader* loader, const blink::WebURLError&) override; @@ -185,7 +185,7 @@ void SetBitrate(int bitrate); // Return the |first_byte_position| passed into the ctor. - int64 first_byte_position() const; + int64_t first_byte_position() const; // Parse a Content-Range header into its component pieces and return true if // each of the expected elements was found & parsed correctly. @@ -193,9 +193,10 @@ // "/*". // NOTE: only public for testing! This is an implementation detail of // VerifyPartialResponse (a private method). - static bool ParseContentRange( - const std::string& content_range_str, int64* first_byte_position, - int64* last_byte_position, int64* instance_size); + static bool ParseContentRange(const std::string& content_range_str, + int64_t* first_byte_position, + int64_t* last_byte_position, + int64_t* instance_size); // Cancels and closes any outstanding deferred ActiveLoader instances. Does // not report a failed state, so subsequent read calls to cache may still @@ -285,8 +286,8 @@ GURL url_; CORSMode cors_mode_; - const int64 first_byte_position_; - const int64 last_byte_position_; + const int64_t first_byte_position_; + const int64_t last_byte_position_; bool single_origin_; // Executed whenever the state of resource loading has changed. @@ -298,16 +299,16 @@ // Members used during request start. StartCB start_cb_; - int64 offset_; - int64 content_length_; - int64 instance_size_; + int64_t offset_; + int64_t content_length_; + int64_t instance_size_; // Members used during a read operation. They should be reset after each // read has completed or failed. ReadCB read_cb_; - int64 read_position_; + int64_t read_position_; int read_size_; - uint8* read_buffer_; + uint8_t* read_buffer_; // Offsets of the requested first byte and last byte in |buffer_|. They are // written by Read().
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 2e14819..5bdc8df7 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -17,6 +17,7 @@ #include "base/metrics/histogram.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" +#include "base/task_runner_util.h" #include "base/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "cc/blink/web_layer_impl.h" @@ -1119,16 +1120,34 @@ void WebMediaPlayerImpl::ReportMemoryUsage() { DCHECK(main_task_runner_->BelongsToCurrentThread()); + // About base::Unretained() usage below: We destroy |demuxer_| on the main + // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the + // media thread and waits for it to finish. Hence, the GetMemoryUsage() task + // posted here must finish earlier. + + if (demuxer_) { + base::PostTaskAndReplyWithResult( + media_task_runner_.get(), FROM_HERE, + base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())), + base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr())); + } else { + FinishMemoryUsageReport(0); + } +} + +void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) { + DCHECK(main_task_runner_->BelongsToCurrentThread()); + const PipelineStatistics stats = pipeline_.GetStatistics(); const int64_t current_memory_usage = stats.audio_memory_usage + stats.video_memory_usage + (data_source_ ? data_source_->GetMemoryUsage() : 0) + - (demuxer_ ? demuxer_->GetMemoryUsage() : 0); + demuxer_memory_usage; DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage << ", Video: " << stats.video_memory_usage << ", DataSource: " << (data_source_ ? data_source_->GetMemoryUsage() : 0) - << ", Demuxer: " << (demuxer_ ? demuxer_->GetMemoryUsage() : 0); + << ", Demuxer: " << demuxer_memory_usage; const int64_t delta = current_memory_usage - last_reported_memory_usage_; last_reported_memory_usage_ = current_memory_usage;
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 35cda62..7cff462 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -238,7 +238,10 @@ // Called at low frequency to tell external observers how much memory we're // using for video playback. Called by |memory_usage_reporting_timer_|. + // Memory usage reporting is done in two steps, because |demuxer_| must be + // accessed on the media thread. void ReportMemoryUsage(); + void FinishMemoryUsageReport(int64_t demuxer_memory_usage); blink::WebLocalFrame* frame_;
diff --git a/mojo/edk/embedder/platform_channel_pair_posix.cc b/mojo/edk/embedder/platform_channel_pair_posix.cc index 7ad1eea..d0968606 100644 --- a/mojo/edk/embedder/platform_channel_pair_posix.cc +++ b/mojo/edk/embedder/platform_channel_pair_posix.cc
@@ -5,10 +5,13 @@ #include "mojo/edk/embedder/platform_channel_pair.h" #include <fcntl.h> +#include <stdint.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> +#include <limits> + #include "base/command_line.h" #include "base/logging.h" #include "base/posix/global_descriptors.h" @@ -48,7 +51,8 @@ // Store a common id in the SO_PEEK_OFF option (which we don't use since we // don't peek) as a way of determining later if two sockets are connected to // each other. - int identifier = base::RandInt(kint32min, kint32max); + int identifier = base::RandInt(std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max()); setsockopt(fds[0], SOL_SOCKET, SO_PEEK_OFF, &identifier, sizeof(identifier)); setsockopt(fds[1], SOL_SOCKET, SO_PEEK_OFF, &identifier, sizeof(identifier));
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc index 8b572288..8f817e3b 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.cc +++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1410,9 +1410,10 @@ } void MojoGLES2Impl::ResizeCHROMIUM(GLuint width, GLuint height, - GLfloat scale_factor) { + GLfloat scale_factor, + GLboolean alpha) { MojoGLES2MakeCurrent(context_); - glResizeCHROMIUM(width, height, scale_factor); + glResizeCHROMIUM(width, height, scale_factor, alpha); } const GLchar* MojoGLES2Impl::GetRequestableExtensionsCHROMIUM() { MojoGLES2MakeCurrent(context_);
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h index 4b43bb97..e207ca49 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.h +++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -649,7 +649,8 @@ void UnmapTexSubImage2DCHROMIUM(const void* mem) override; void ResizeCHROMIUM(GLuint width, GLuint height, - GLfloat scale_factor) override; + GLfloat scale_factor, + GLboolean alpha) override; const GLchar* GetRequestableExtensionsCHROMIUM() override; void RequestExtensionCHROMIUM(const char* extension) override; void GetProgramInfoCHROMIUM(GLuint program,
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h index c9b1c0a..a6c8585 100644 --- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h +++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -140,10 +140,11 @@ GLenum access), (target, level, xoffset, yoffset, width, height, format, type, access)) VISIT_GL_CALL(UnmapTexSubImage2DCHROMIUM, void, (const void* mem), (mem)) -VISIT_GL_CALL(ResizeCHROMIUM, - void, - (GLuint width, GLuint height, GLfloat scale_factor), - (width, height, scale_factor)) +VISIT_GL_CALL( + ResizeCHROMIUM, + void, + (GLuint width, GLuint height, GLfloat scale_factor, GLboolean alpha), + (width, height, scale_factor, alpha)) VISIT_GL_CALL(GetRequestableExtensionsCHROMIUM, const GLchar*, (), ()) VISIT_GL_CALL(RequestExtensionCHROMIUM, void,
diff --git a/mojo/public/cpp/bindings/callback.h b/mojo/public/cpp/bindings/callback.h index beec1a10..8b4c158 100644 --- a/mojo/public/cpp/bindings/callback.h +++ b/mojo/public/cpp/bindings/callback.h
@@ -5,6 +5,8 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ #define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ +#include <utility> + #include "mojo/public/cpp/bindings/lib/callback_internal.h" #include "mojo/public/cpp/bindings/lib/shared_ptr.h" #include "mojo/public/cpp/bindings/lib/template_util.h" @@ -24,7 +26,11 @@ struct Runnable { virtual ~Runnable() {} virtual void Run( - // ForwardType ensures String is passed as a const reference. + // ForwardType ensures String is passed as a const reference. Can't use + // universal refs (Args&&) here since this method itself isn't templated + // because it is a virtual interface. So we have to take the arguments + // all by value (except String which we take as a const reference due to + // ForwardType). typename internal::Callback_ParamTraits<Args>::ForwardType...) const = 0; }; @@ -52,11 +58,13 @@ typename internal::Callback_ParamTraits<Args>::ForwardType...)) : sink_(new FunctionPtrAdapter(function_ptr)) {} - // Executes the callback function, invoking Pass() on move-only types. + // Executes the callback function. void Run(typename internal::Callback_ParamTraits<Args>::ForwardType... args) const { if (sink_.get()) - sink_->Run(internal::Forward(args)...); + sink_->Run(std::forward< + typename internal::Callback_ParamTraits<Args>::ForwardType>( + args)...); } bool is_null() const { return !sink_.get(); } @@ -73,7 +81,9 @@ virtual void Run( typename internal::Callback_ParamTraits<Args>::ForwardType... args) const override { - sink.Run(internal::Forward(args)...); + sink.Run(std::forward< + typename internal::Callback_ParamTraits<Args>::ForwardType>( + args)...); } Sink sink; }; @@ -85,23 +95,32 @@ virtual void Run( typename internal::Callback_ParamTraits<Args>::ForwardType... args) const override { - sink.operator()(internal::Forward(args)...); + sink.operator()( + std::forward< + typename internal::Callback_ParamTraits<Args>::ForwardType>( + args)...); } Sink sink; }; // Adapts a function pointer. struct FunctionPtrAdapter : public Runnable { - explicit FunctionPtrAdapter(void (*function_ptr)( - typename internal::Callback_ParamTraits<Args>::ForwardType...)) + private: + using FunctionPtr = + void (*)(typename internal::Callback_ParamTraits<Args>::ForwardType...); + + public: + explicit FunctionPtrAdapter(FunctionPtr function_ptr) : function_ptr(function_ptr) {} virtual void Run( typename internal::Callback_ParamTraits<Args>::ForwardType... args) const override { - (*function_ptr)(internal::Forward(args)...); + (*function_ptr)( + std::forward< + typename internal::Callback_ParamTraits<Args>::ForwardType>( + args)...); } - void (*function_ptr)( - typename internal::Callback_ParamTraits<Args>::ForwardType...); + FunctionPtr function_ptr; }; internal::SharedPtr<Runnable> sink_;
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h index 6b9e54f..b6168033 100644 --- a/mojo/public/cpp/bindings/lib/array_serialization.h +++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -7,6 +7,7 @@ #include <string.h> // For |memcpy()|. +#include <utility> #include <vector> #include "mojo/public/c/system/macros.h" @@ -326,7 +327,7 @@ internal::Array_Data<F>::New(input.size(), buf); if (result) { internal::ArraySerializer<E, F>::SerializeElements( - internal::Forward(input), buf, result, validate_params); + std::move(input), buf, result, validate_params); } *output = result; } else {
diff --git a/mojo/public/cpp/bindings/lib/template_util.h b/mojo/public/cpp/bindings/lib/template_util.h index 9a5788c..ceaf8e0 100644 --- a/mojo/public/cpp/bindings/lib/template_util.h +++ b/mojo/public/cpp/bindings/lib/template_util.h
@@ -60,18 +60,6 @@ sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value; }; -// Returns a reference to |t| when T is not a move-only type. -template <typename T> -typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) { - return t; -} - -// Returns the result of t.Pass() when T is a move-only type. -template <typename T> -typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) { - return t.Pass(); -} - // This goop is a trick used to implement a template that can be used to // determine if a given class is the base class of another given class. template <typename, typename>
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl index 011433e9..f28948a 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -47,19 +47,18 @@ {%- if kind|is_array_kind %} const mojo::internal::ArrayValidateParams {{name}}_validate_params( {{kind|get_array_validate_params_ctor_args|indent(10)}}); - mojo::SerializeArray_(mojo::internal::Forward({{input_field}}), {{buffer}}, + mojo::SerializeArray_(std::move({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr, &{{name}}_validate_params); {%- elif kind|is_map_kind %} const mojo::internal::ArrayValidateParams {{name}}_validate_params( {{kind.value_kind|get_map_validate_params_ctor_args|indent(10)}}); - mojo::SerializeMap_( - mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr, - &{{name}}_validate_params); + mojo::SerializeMap_(std::move({{input_field}}), {{buffer}}, + &{{output}}->{{name}}.ptr, &{{name}}_validate_params); {%- elif kind|is_union_kind %} internal::{{kind.name}}_Data* {{name}}_ptr = &{{output}}->{{name}}; - SerializeUnion_(mojo::internal::Forward({{input_field}}), {{buffer}}, &{{name}}_ptr, true); + SerializeUnion_(std::move({{input_field}}), {{buffer}}, &{{name}}_ptr, true); {%- else %} - Serialize_(mojo::internal::Forward({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); + Serialize_(std::move({{input_field}}), {{buffer}}, &{{output}}->{{name}}.ptr); {%- endif %} {%- if not kind|is_nullable_kind %} MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl index 7f53e813..3471932 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
@@ -48,23 +48,23 @@ buf, &result->data.f_{{field.name}}.ptr); {% elif field.kind|is_struct_kind %} Serialize_( - mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + std::move(*(input_acc.data()->{{field.name}})), buf, &result->data.f_{{field.name}}.ptr); {% elif field.kind|is_union_kind %} SerializeUnion_( - mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + std::move(*(input_acc.data()->{{field.name}})), buf, &result->data.f_{{field.name}}.ptr, false); {% elif field.kind|is_array_kind %} const mojo::internal::ArrayValidateParams {{field.name}}_validate_params( {{field.kind|get_array_validate_params_ctor_args|indent(16)}}); SerializeArray_( - mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + std::move(*(input_acc.data()->{{field.name}})), buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params); {% elif field.kind|is_map_kind %} const mojo::internal::ArrayValidateParams {{field.name}}_validate_params( {{field.kind.value_kind|get_map_validate_params_ctor_args|indent(16)}}); SerializeMap_( - mojo::internal::Forward(*(input_acc.data()->{{field.name}})), + std::move(*(input_acc.data()->{{field.name}})), buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params); {%- endif %} {% elif field.kind|is_any_handle_kind %}
diff --git a/mojo/runner/host/linux_sandbox.cc b/mojo/runner/host/linux_sandbox.cc index 23b84432..a8dcb8b 100644 --- a/mojo/runner/host/linux_sandbox.cc +++ b/mojo/runner/host/linux_sandbox.cc
@@ -6,6 +6,7 @@ #include <fcntl.h> #include <sys/syscall.h> +#include <utility> #include "base/bind.h" #include "base/debug/leak_annotations.h" @@ -83,7 +84,11 @@ case __NR_sched_getaffinity: return sandbox::RestrictSchedTarget(policy_pid(), sysno); case __NR_ftruncate: +#if defined(__NR_getrlimit) + // __NR_getrlimit does not exist on all systems (e.g. in the arm/linux + // build). case __NR_getrlimit: +#endif case __NR_uname: case __NR_getsockopt: case __NR_setsockopt: @@ -135,7 +140,7 @@ base::ScopedFD proc_fd(HANDLE_EINTR( openat(proc_fd_.get(), ".", O_RDONLY | O_DIRECTORY | O_CLOEXEC))); CHECK(proc_fd.is_valid()); - sandbox.SetProcFd(proc_fd.Pass()); + sandbox.SetProcFd(std::move(proc_fd)); CHECK( sandbox.StartSandbox(sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED)) << "Starting the process with a sandbox failed. Missing kernel support.";
diff --git a/mojo/util/capture_util.h b/mojo/util/capture_util.h index 4b89eb7..dfac270 100644 --- a/mojo/util/capture_util.h +++ b/mojo/util/capture_util.h
@@ -5,29 +5,31 @@ #ifndef MOJO_UTIL_CAPTURE_UTIL_H_ #define MOJO_UTIL_CAPTURE_UTIL_H_ -#include "mojo/public/cpp/bindings/lib/template_util.h" +#include <utility> + +#include "mojo/public/cpp/bindings/callback.h" namespace mojo { template <typename T1> mojo::Callback<void(T1)> Capture(T1* t1) { - return [t1](T1 got_t1) { *t1 = mojo::internal::Forward(got_t1); }; + return [t1](T1 got_t1) { *t1 = std::move(got_t1); }; } template <typename T1, typename T2> mojo::Callback<void(T1, T2)> Capture(T1* t1, T2* t2) { return [t1, t2](T1 got_t1, T2 got_t2) { - *t1 = mojo::internal::Forward(got_t1); - *t2 = mojo::internal::Forward(got_t2); + *t1 = std::move(got_t1); + *t2 = std::move(got_t2); }; } template <typename T1, typename T2, typename T3> mojo::Callback<void(T1, T2, T3)> Capture(T1* t1, T2* t2, T3* t3) { return [t1, t2, t3](T1 got_t1, T2 got_t2, T3 got_t3) { - *t1 = mojo::internal::Forward(got_t1); - *t2 = mojo::internal::Forward(got_t2); - *t3 = mojo::internal::Forward(got_t3); + *t1 = std::move(got_t1); + *t2 = std::move(got_t2); + *t3 = std::move(got_t3); }; }
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc index b83cc18..a36e5ce 100644 --- a/net/base/file_stream_unittest.cc +++ b/net/base/file_stream_unittest.cc
@@ -13,9 +13,9 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/synchronization/waitable_event.h" +#include "base/test/sequenced_worker_pool_owner.h" #include "base/test/test_timeouts.h" #include "base/thread_task_runner_handle.h" -#include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -714,11 +714,10 @@ } TEST_F(FileStreamTest, OpenAndDelete) { - scoped_refptr<base::SequencedWorkerPool> pool( - new base::SequencedWorkerPool(1, "StreamTest")); + base::SequencedWorkerPoolOwner pool_owner(1, "StreamTest"); bool prev = base::ThreadRestrictions::SetIOAllowed(false); - scoped_ptr<FileStream> stream(new FileStream(pool.get())); + scoped_ptr<FileStream> stream(new FileStream(pool_owner.pool())); int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE | base::File::FLAG_ASYNC; TestCompletionCallback open_callback; @@ -730,14 +729,12 @@ stream.reset(); // Force an operation through the pool. - scoped_ptr<FileStream> stream2(new FileStream(pool.get())); + scoped_ptr<FileStream> stream2(new FileStream(pool_owner.pool())); TestCompletionCallback open_callback2; rv = stream2->Open(temp_file_path(), flags, open_callback2.callback()); EXPECT_EQ(OK, open_callback2.GetResult(rv)); stream2.reset(); - pool->Shutdown(); - // open_callback won't be called. base::RunLoop().RunUntilIdle(); EXPECT_FALSE(open_callback.have_result());
diff --git a/net/base/network_quality_estimator_unittest.cc b/net/base/network_quality_estimator_unittest.cc index 038ab62..729af9d 100644 --- a/net/base/network_quality_estimator_unittest.cc +++ b/net/base/network_quality_estimator_unittest.cc
@@ -716,8 +716,8 @@ std::map<std::string, std::string> variation_params; TestNetworkQualityEstimator estimator(variation_params); base::TimeTicks now = base::TimeTicks::Now(); - base::TimeTicks old = - base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1); + base::TimeTicks old = now - base::TimeDelta::FromMilliseconds(1); + ASSERT_NE(old, now); // First sample has very old timestamp. estimator.downstream_throughput_kbps_observations_.AddObservation(
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc index ec9342ac..362f7ff 100644 --- a/net/cert/x509_certificate_unittest.cc +++ b/net/cert/x509_certificate_unittest.cc
@@ -1175,7 +1175,7 @@ // need to be renegerated with a larger key. See https://crbug.com/472291. {"large_key.pem", 0, X509Certificate::kPublicKeyTypeUnknown}, #else - {"large_key.pem", 4104, X509Certificate::kPublicKeyTypeRSA}, + {"large_key.pem", 8200, X509Certificate::kPublicKeyTypeRSA}, #endif };
diff --git a/net/data/ssl/certificates/large_key.pem b/net/data/ssl/certificates/large_key.pem index 8ccb287b..fe8a1d6 100644 --- a/net/data/ssl/certificates/large_key.pem +++ b/net/data/ssl/certificates/large_key.pem
@@ -1,112 +1,194 @@ Certificate: Data: Version: 1 (0x0) - Serial Number: - fa:ba:a5:10:ef:85:bb:70 - Signature Algorithm: sha256WithRSAEncryption + Serial Number: 10746871423479549511 (0x95248e9ecb4b8e47) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 Validity - Not Before: Apr 23 21:32:21 2015 GMT - Not After : Apr 20 21:32:21 2025 GMT + Not Before: Dec 2 20:57:39 2015 GMT + Not After : Nov 29 20:57:39 2025 GMT Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (4104 bit) - Modulus (4104 bit): - 00:c9:98:35:7d:a5:d4:41:1b:83:60:84:76:14:c2: - 0d:a6:7f:e7:52:15:a5:7c:96:96:56:b8:98:f9:bc: - 94:56:23:14:f2:74:05:e6:ba:d9:3a:58:dd:b5:03: - 9c:d1:f5:47:76:c2:45:78:f9:b8:e1:44:40:45:08: - 2d:d1:ff:c3:bf:d7:b2:4a:94:6a:61:37:dd:cb:66: - 22:28:8d:cc:5f:35:dd:9a:1a:d5:0e:cc:36:76:ae: - 65:a2:96:d3:cd:de:8d:b4:c9:28:a8:a8:2d:45:89: - 98:aa:7d:9e:12:7b:e1:a5:ba:d9:56:8a:4a:1f:1c: - 7d:e2:cf:f5:f0:54:38:6d:47:4c:1d:1c:22:3c:74: - 72:4b:fd:c2:97:66:b1:9c:8e:c3:d6:88:5e:6a:ed: - c9:fe:b7:d9:ef:03:25:5d:da:4a:ab:5e:fa:f4:a8: - 87:30:90:00:85:a6:5b:40:77:b6:34:64:63:58:05: - cd:1e:58:d6:fd:b2:13:51:ba:a4:9f:7f:e3:db:88: - 88:58:1f:df:5f:67:cc:49:0a:bb:e0:ce:d9:3f:ce: - 26:20:1e:35:f3:f0:8a:bd:8b:8b:4f:16:80:53:4e: - 44:3b:1a:9e:60:6b:ff:cf:f7:9f:40:bf:d2:86:e4: - 79:39:3a:d7:5a:bd:d0:63:cf:f6:54:e1:9e:09:e7: - 63:8a:17:33:bf:f2:5f:ec:ee:45:18:52:ee:e7:23: - a2:a8:af:d2:85:4b:bb:f9:12:ba:35:22:d2:5e:9c: - 42:2d:66:e1:01:02:d4:0f:ff:86:1c:91:8f:55:9c: - 9f:24:4e:17:c8:23:c1:a7:4e:39:ed:4b:dc:b8:c4: - 3f:7d:c9:0f:ff:01:40:4d:dd:9a:55:29:84:f8:52: - 72:da:38:32:9a:ef:2b:2e:67:5b:d2:2d:70:46:91: - 42:79:22:a2:08:c0:fd:24:95:9e:04:a6:5c:9e:c0: - ed:25:2a:57:62:17:b7:c0:12:d4:8b:59:f3:db:8b: - cd:95:4f:d9:32:f2:f0:e1:14:9b:db:73:e7:b4:97: - a6:90:f7:0d:cb:59:93:94:12:2a:c1:28:7d:3c:bd: - b5:7e:bb:13:c0:4c:ef:ce:20:3d:3b:4f:84:25:77: - dc:1f:0f:08:dd:76:9c:ad:7d:00:2f:23:42:6a:37: - e9:d0:6b:8e:9a:6f:3b:46:09:74:23:43:a9:58:46: - 62:33:69:2a:0c:df:cd:6c:75:88:f1:01:3d:67:e0: - a8:e3:bd:23:03:66:f3:11:f2:07:a8:bf:4b:c9:81: - ce:a9:ed:8d:48:a6:10:15:fb:79:27:ae:2e:8f:35: - c5:39:12:eb:f2:b7:28:d3:b3:e7:4c:71:d8:e1:d1: - f7:39:94:87 + Public-Key: (8200 bit) + Modulus: + 00:df:c1:08:64:7a:31:df:14:95:3f:cd:6d:83:9c: + 3f:9d:f6:31:ce:29:40:76:5b:4f:9c:f2:5f:a5:bf: + d4:82:eb:67:1d:1a:18:c5:43:53:b6:9c:19:de:87: + da:53:fe:11:e8:cd:49:b6:5c:98:68:dc:ae:b2:3e: + 86:03:8a:a5:eb:a5:95:1a:01:b6:b7:67:84:5a:07: + cd:90:06:69:52:db:10:b8:73:f6:0f:e2:43:28:4b: + 5f:42:75:c9:78:65:bb:2d:4b:b9:e9:97:09:be:1f: + 49:5e:57:86:c7:3f:fb:eb:18:90:57:7e:86:c0:e1: + 77:ec:67:6e:27:eb:f7:80:7a:e6:b1:dd:78:c9:f2: + ef:1b:10:3e:e2:6f:89:8b:56:8d:69:d7:f0:1b:1e: + 35:d6:41:c6:1a:80:1f:15:be:0e:ae:c9:87:df:e8: + 80:a2:85:20:de:32:3a:f8:cc:12:72:eb:41:1e:2b: + 2a:29:3f:f7:e1:eb:29:99:ad:b4:8d:79:0a:99:8e: + 0f:4a:1f:44:e9:74:b7:17:cb:97:21:7a:7d:d5:6c: + a5:fd:d1:53:b5:21:8c:0a:53:4d:0a:e9:4d:40:52: + 0b:35:5f:40:09:09:1f:6d:b6:04:9c:75:f2:ee:32: + 89:d8:ff:a3:5b:37:93:69:f0:25:4c:ec:2a:a7:1e: + e2:29:33:ef:07:f4:61:8c:91:a9:bb:f9:89:ba:b2: + dd:98:08:91:bf:77:f6:bb:3b:f7:8a:f7:1c:d7:6b: + 17:d3:fa:62:12:2e:bb:d3:bf:78:a3:eb:1e:cb:00: + 70:6e:87:3f:9e:eb:fd:2d:32:77:f2:31:af:5c:dc: + 15:a7:2c:d9:ae:e7:fb:f8:01:4a:c9:45:f3:87:dc: + c7:cc:14:fe:7f:7d:46:94:08:ac:25:6a:18:02:49: + b5:aa:bd:4f:c5:1a:04:b8:ac:a1:6a:54:01:19:05: + f4:55:e0:08:98:67:f5:ec:61:09:ec:fc:81:9b:88: + 77:53:7a:d1:48:4c:8f:e2:b7:0d:06:04:bc:05:6e: + 0f:0a:a1:56:07:b1:13:41:90:49:fd:12:70:f6:01: + 57:ad:d6:2d:a2:a1:04:cf:d1:29:38:f5:68:76:58: + 9b:5d:1e:0f:2c:77:f6:f0:cf:d8:df:c5:d2:23:8b: + 34:a9:ae:94:67:74:4b:21:99:7c:bb:de:be:f9:5c: + b6:eb:14:2d:bb:38:56:fb:0c:7c:70:42:42:1b:1b: + 3c:98:6d:61:1f:16:32:ce:73:2a:23:9e:eb:e6:d1: + 89:0d:30:07:d2:94:09:8c:6d:38:49:e6:07:fd:bd: + 23:48:47:6c:ca:c0:da:50:e8:5f:06:08:72:e1:ca: + fd:91:fc:29:fc:26:40:ff:1d:78:16:23:1f:c2:64: + 41:04:b6:3c:40:b7:08:27:a6:7d:26:4a:fd:57:af: + ee:ba:e3:93:45:07:64:5c:5f:c0:a7:e8:a2:5b:a7: + 3d:da:d3:97:1f:7c:da:77:00:0d:30:3e:e3:ae:fd: + 4c:c7:18:e6:62:e0:9d:74:0f:90:00:aa:c2:32:de: + dc:d1:8f:d7:c3:c2:08:bf:d1:bd:7e:21:09:79:32: + 8f:1a:12:43:97:91:41:33:bd:d4:2e:3b:a9:6d:06: + 23:d1:da:7e:5f:45:27:d5:17:9c:0e:df:2c:d1:66: + cb:ed:ec:e3:c3:6b:ab:0d:ba:71:04:a4:92:a4:71: + 55:69:20:35:72:fd:ad:54:a8:cf:44:c3:9d:a1:5a: + 94:4d:05:62:5e:98:d6:25:c5:d6:cf:f5:ef:94:c0: + 2c:53:87:0b:9f:13:0f:63:c5:97:d5:5b:8a:46:7c: + 0e:28:de:66:96:74:df:2a:b2:b0:27:6d:4c:4f:54: + 72:d9:2d:ae:58:4f:d3:63:63:93:c2:34:57:66:3b: + 38:90:36:a9:a9:95:e6:7d:e8:84:87:68:73:9b:44: + 68:d9:69:1f:1c:1b:9d:58:44:77:72:e8:28:c1:1a: + 11:bd:5c:40:b7:d0:58:b9:58:91:9f:5b:30:94:33: + fa:f6:be:2a:59:8b:43:cc:e3:04:45:1b:43:7e:d7: + b5:f4:d3:dc:5d:65:ae:6b:d1:92:d2:f7:b6:8f:df: + c6:5c:00:c3:0b:37:28:33:33:dd:05:cb:3c:62:0d: + 0b:54:42:ea:9f:6c:e9:f2:ef:c7:ab:7c:5c:cf:18: + 55:35:1c:f7:72:8f:c3:d5:1b:c0:09:6f:44:e8:06: + 62:44:c4:0b:10:e2:c3:b1:9c:de:73:37:5d:51:bc: + b6:3f:38:1b:75:d9:26:df:4f:1a:eb:63:9c:e1:49: + 11:e4:cb:ec:e3:3a:b1:e2:00:8b:92:bb:73:fb:05: + 78:81:e7:ac:21:1b:23:c1:8f:8b:9c:52:bb:09:da: + 72:23:bf:81:e6:74:18:63:1f:84:9b:5d:06:92:72: + aa:84:50:f4:8f:2a:94:05:8f:42:5f:de:45:05:b2: + be:26:3d:dc:c4:ef:83:cb:aa:b4:67:2f:5c:e2:f9: + b3:9c:1f:f9:92:8f:40:4f:99:df:9a:5e:fd:c5:db: + 92:dc:a8:41:13:64:f4:bb:0a:65:87:dc:cf:39:30: + be:9e:3a:86:62:d6:2e:6f:17:8a:d9:77:3a:e2:8d: + 8f:08:eb:1e:fd:af:67:22:1d:ff:ff:b8:22:2b:93: + 51:1d:12:c7:6b:85:4d:b7:18:96:64:e2:25:06:ec: + 45:67:63:2b:b1:23 Exponent: 65537 (0x10001) Signature Algorithm: sha256WithRSAEncryption - 2d:3b:5f:58:30:58:97:65:d0:36:a6:03:0c:6b:bc:a6:5b:e7: - 8f:a3:a7:05:5d:db:9b:3f:0e:22:89:3e:e1:00:91:3c:17:ab: - 10:10:80:f5:d1:f9:cb:d7:38:9e:bc:36:a0:31:d2:e3:2f:98: - 62:d8:a2:cd:73:7c:56:29:b0:c0:41:01:71:50:70:7a:b2:9d: - b6:ad:13:71:d8:19:7d:4f:7a:be:4b:36:2e:d7:f7:81:53:a7: - e0:7f:04:77:09:84:a3:56:22:48:7e:6d:ca:20:12:ed:a7:da: - 29:cf:46:46:81:8f:97:4b:17:63:25:f2:18:48:c1:82:21:c7: - be:4f:54:29:88:29:78:d0:be:98:9c:d9:4f:76:e7:6b:a2:10: - 4a:ce:45:02:c7:5e:5a:ac:5f:0e:4b:a3:51:a9:ec:7a:3f:a0: - 51:49:75:bc:af:f4:89:88:35:69:65:15:a5:33:c5:2f:1e:c5: - 30:98:6b:04:14:b9:29:b5:31:76:23:88:32:72:29:e4:16:de: - bb:95:d6:bb:48:e5:38:37:57:6e:8a:2f:c0:64:2c:01:4d:e6: - 69:9e:ae:4a:39:87:96:5d:50:e6:25:08:46:77:ea:da:4d:b2: - bd:5e:44:ca:e2:46:b1:7a:4a:3d:83:16:a9:a6:e5:c4:ef:fc: - af:77:58:6e:3b:cd:b3:b3:0e:d2:59:d2:be:16:ac:64:fa:f7: - b1:06:02:7d:c9:8a:06:65:73:da:d8:a8:02:41:d5:68:41:7a: - 0f:a7:5c:90:b3:6f:01:66:65:96:4c:50:bd:c7:38:67:61:21: - 52:dc:a9:f0:f7:0b:16:95:2d:5d:b8:0b:da:9a:fe:f8:4c:e9: - fa:6a:32:a7:d4:67:7b:21:45:7a:4e:7c:a6:fa:cb:65:3d:8f: - 38:90:5a:29:7d:7f:21:32:6d:c6:61:70:f9:a8:4e:3f:9b:3c: - f0:4b:40:d6:7d:e5:d6:31:08:ff:29:21:f9:e7:81:36:1a:86: - d5:96:06:1d:1e:b1:fc:4c:e3:6d:ce:3a:2c:16:b8:03:76:f3: - 70:77:15:ea:b5:32:c3:f5:9f:a6:61:e1:29:bb:88:2c:a0:cf: - 05:f5:3d:97:ae:b5:b9:01:e8:2f:5e:54:17:2e:09:5b:ea:d0: - 4a:95:65:d9:cf:83:3a:bc:1d:7d:28:4b:7b:8d:5c:ef:8a:06: - f9:64:b5:ec:3f:73:fc:6c:58:cc:57:da:d3:5d:5e:b5:58:43: - 53:27:f0:49:01:e4:45:8d:eb:68:f3:40:fc:ec:63:62:ce:c3: - d9:97:d3:a3:51:8c:c5:09:a9:81:6e:23:e0:6a:1f:02:b0:f8: - b0:40:0c:2f:ea:ee:c2:1f:1b + ba:7f:75:5f:5f:e6:a9:7a:b2:53:a8:d4:02:60:21:29:ce:a5: + e3:95:8a:eb:22:d0:54:f3:76:1b:22:a4:bd:2b:fe:a0:0e:f4: + 46:8a:c4:b4:ee:58:ca:c0:dc:7a:1c:26:30:99:85:ed:e5:ae: + 3a:23:81:76:5b:b4:e8:50:33:6f:19:52:a6:03:82:c7:13:ce: + 4f:97:af:d7:42:6e:28:0f:f2:cf:e6:eb:f9:e9:65:40:2e:92: + 44:87:ac:f7:a3:65:84:a6:46:1e:c6:3c:23:9a:98:13:d8:f3: + ce:a0:20:06:d3:6a:ec:db:3f:d7:92:5c:01:a7:e1:c1:d9:ba: + 6f:1b:41:0f:ff:6d:80:dd:df:69:1b:45:36:f1:e4:1d:72:96: + 57:3d:8a:80:e3:ae:b4:91:8e:88:40:48:e6:33:0d:e7:ad:3f: + aa:d3:c1:96:f2:44:73:bb:51:56:ce:75:b5:e9:2d:f0:a7:9f: + 68:da:bb:17:9e:b4:c1:a2:81:15:be:28:43:f7:2c:20:35:94: + 17:33:99:52:33:8b:7b:72:12:27:df:88:29:11:93:2e:55:8a: + eb:63:56:14:e9:cb:58:e3:a6:52:e4:21:04:48:fc:09:a0:30: + 8a:8c:cf:df:b2:6c:5c:d3:96:0a:59:26:70:b5:fa:d0:1a:cf: + 06:e9:30:f8:a2:45:52:63:43:c9:8d:ee:13:35:c4:6d:fc:f9: + 16:4f:f7:5c:56:16:1a:1f:17:6c:f6:2e:20:d6:ec:57:0f:fa: + 34:1c:a7:b5:18:fa:7d:16:54:71:3e:cd:97:70:f8:b9:7d:ea: + 67:83:50:74:4d:a7:c5:90:a8:51:50:50:61:c9:31:06:63:7a: + 8d:3c:b9:eb:f5:31:3c:fa:be:4a:1e:2d:02:26:cb:7d:fb:54: + 21:16:7a:06:72:34:fd:1a:9c:36:9f:d0:4a:bf:df:86:74:0f: + fc:df:bf:32:6a:41:ae:24:67:a1:4a:f7:c8:cd:a1:6a:9b:c5: + 69:db:72:94:b9:85:13:ab:20:25:77:b2:2f:a4:40:ec:e9:0f: + 68:b2:a8:f7:78:50:f5:5b:30:6b:67:4a:f0:ca:57:18:0d:54: + 9a:bd:e4:33:24:9c:51:4a:6f:99:92:3e:05:0b:a8:d1:9f:a8: + d4:54:28:b0:8b:be:0a:ff:64:76:aa:76:7c:f0:23:3f:c1:8d: + 91:4f:04:37:2c:30:90:1e:6d:60:41:88:9d:b5:7b:0a:1b:98: + e5:15:58:47:d8:fd:11:d0:0f:5d:ec:6c:65:fd:3c:b1:4a:a4: + 7a:79:bd:e9:4d:4d:39:7b:9b:30:76:11:1c:c5:df:51:5b:7e: + 7b:44:1e:25:44:35:f3:71:19:3b:d4:7a:5e:db:3a:3c:85:54: + 0f:b1:d9:1d:ab:69:88:04:a1:2e:37:77:8d:97:aa:24:17:af: + 54:71:9f:ff:1d:74:e9:f3:7d:c8:79:e9:08:59:5f:dc:0e:d8: + b7:5b:fa:ee:4c:07:cf:51:fb:e7:5b:7c:d0:d5:85:f9:08:9c: + 81:6a:83:f7:15:cd:fc:4d:a5:a7:39:6b:b2:cc:f2:e9:90:b7: + ea:e5:5e:3a:a0:a9:1d:e5:8d:2f:80:9b:30:8a:f0:ff:d5:c2: + a6:0e:83:7b:80:ec:f4:7b:88:f4:ad:69:01:81:35:94:14:0c: + 8e:50:93:a5:39:17:5b:06:e0:70:3c:f9:6e:5e:09:89:84:23: + 74:12:42:82:22:78:bc:aa:64:d3:51:f4:c6:96:8a:33:19:56: + bb:21:6f:bd:dd:c9:0b:69:0e:2c:17:5e:67:12:64:08:21:fd: + 2e:5b:49:14:6e:9f:47:86:a4:99:4b:06:a5:50:20:30:a4:c7: + fb:32:d5:b6:5b:74:82:4c:7a:d0:e2:2b:99:7a:67:69:7a:3e: + d0:4e:65:eb:d3:ad:41:83:71:e1:c3:c7:69:36:03:ac:e4:0b: + cd:26:d7:00:36:88:26:36:22:fe:d4:d5:4f:79:5a:88:10:55: + 98:0d:e6:e3:49:c8:fb:b5:b3:b8:5c:cb:a3:57:80:a8:06:34: + 32:57:70:0a:df:78:d4:d1:f9:cc:27:ef:17:2e:38:26:e6:32: + ff:7d:a7:f8:44:b3:52:00:4c:a0:af:76:6a:a3:99:c2:a7:73: + c8:fd:9c:fa:40:c8:48:0f:83:e8:03:3f:2b:7e:3a:bc:3b:6c: + 43:af:2b:ca:a3:29:a7:2a:d2:c2:22:90:98:fb:7e:33:79:c3: + 6d:b9:56:96:bd:6d:f5:57:cf:79:03:77:e6:85:17:d2:7b:5a: + 67:6d:03:b2:cc:e0:4f:81:56:d7:54:f7:cd:31:c7:bd:cf:d4: + 19:9f:99:1b:91:69:28:9b:09:27:77:28:de:4f:cb:2a:38:4d: + 29:28:de:4f:a4:d4:e4:09:a2:a4:ca:dd:86:e4:fd:3b:95:1a: + 5a:74:9f:3b:af:32:d0:25:7a:67:c3:de:c6:93:0e:8a:6b:1e: + 79:89:4c:0c:86:91:cf:b5:bd:b3:3d:6c:c0:26:74:83:49:62: + cc:51:83:3a:e7:08:bb:17:67:17:c2:fa:9a:af:86:57:b8:44: + a6:3f:af:8f:21:85:bd:88:5b:ff:1b:af:78:3b:aa:90:74:ff: + 3a:f3:18:40:69:4f:35:a6:45:80:ff:99:7b:95:a3:51:1b:e0: + 26:cc:46:41:dc:4a:ca:54:a2:c1:14:d9:44:36:ba:eb:29 -----BEGIN CERTIFICATE----- -MIIFPjCCAyUCCQD6uqUQ74W7cDANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJV +MIIJPjCCBSUCCQCVJI6ey0uORzANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJV UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQ -MA4GA1UECgwHVGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTE1MDQyMzIx -MzIyMVoXDTI1MDQyMDIxMzIyMVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +MA4GA1UECgwHVGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTE1MTIwMjIw +NTczOVoXDTI1MTEyOTIwNTczOVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg -Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCAiMwDQYJKoZIhvcNAQEBBQADggIQADCC -AgsCggICAMmYNX2l1EEbg2CEdhTCDaZ/51IVpXyWlla4mPm8lFYjFPJ0Bea62TpY -3bUDnNH1R3bCRXj5uOFEQEUILdH/w7/XskqUamE33ctmIiiNzF813Zoa1Q7MNnau -ZaKW083ejbTJKKioLUWJmKp9nhJ74aW62VaKSh8cfeLP9fBUOG1HTB0cIjx0ckv9 -wpdmsZyOw9aIXmrtyf632e8DJV3aSqte+vSohzCQAIWmW0B3tjRkY1gFzR5Y1v2y -E1G6pJ9/49uIiFgf319nzEkKu+DO2T/OJiAeNfPwir2Li08WgFNORDsanmBr/8/3 -n0C/0obkeTk611q90GPP9lThngnnY4oXM7/yX+zuRRhS7ucjoqiv0oVLu/kSujUi -0l6cQi1m4QEC1A//hhyRj1WcnyROF8gjwadOOe1L3LjEP33JD/8BQE3dmlUphPhS -cto4MprvKy5nW9ItcEaRQnkiogjA/SSVngSmXJ7A7SUqV2IXt8AS1ItZ89uLzZVP -2TLy8OEUm9tz57SXppD3DctZk5QSKsEofTy9tX67E8BM784gPTtPhCV33B8PCN12 -nK19AC8jQmo36dBrjppvO0YJdCNDqVhGYjNpKgzfzWx1iPEBPWfgqOO9IwNm8xHy -B6i/S8mBzqntjUimEBX7eSeuLo81xTkS6/K3KNOz50xx2OHR9zmUhwIDAQABMA0G -CSqGSIb3DQEBCwUAA4ICAgAtO19YMFiXZdA2pgMMa7ymW+ePo6cFXdubPw4iiT7h -AJE8F6sQEID10fnL1zievDagMdLjL5hi2KLNc3xWKbDAQQFxUHB6sp22rRNx2Bl9 -T3q+SzYu1/eBU6fgfwR3CYSjViJIfm3KIBLtp9opz0ZGgY+XSxdjJfIYSMGCIce+ -T1QpiCl40L6YnNlPdudrohBKzkUCx15arF8OS6NRqex6P6BRSXW8r/SJiDVpZRWl -M8UvHsUwmGsEFLkptTF2I4gycinkFt67lda7SOU4N1duii/AZCwBTeZpnq5KOYeW -XVDmJQhGd+raTbK9XkTK4kaxeko9gxappuXE7/yvd1huO82zsw7SWdK+Fqxk+vex -BgJ9yYoGZXPa2KgCQdVoQXoPp1yQs28BZmWWTFC9xzhnYSFS3Knw9wsWlS1duAva -mv74TOn6ajKn1Gd7IUV6Tnym+stlPY84kFopfX8hMm3GYXD5qE4/mzzwS0DWfeXW -MQj/KSH554E2GobVlgYdHrH8TONtzjosFrgDdvNwdxXqtTLD9Z+mYeEpu4gsoM8F -9T2XrrW5AegvXlQXLglb6tBKlWXZz4M6vB19KEt7jVzvigb5ZLXsP3P8bFjMV9rT -XV61WENTJ/BJAeRFjeto80D87GNizsPZl9OjUYzFCamBbiPgah8CsPiwQAwv6u7C -Hxs= +Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCBCMwDQYJKoZIhvcNAQEBBQADggQQADCC +BAsCggQCAN/BCGR6Md8UlT/NbYOcP532Mc4pQHZbT5zyX6W/1ILrZx0aGMVDU7ac +Gd6H2lP+EejNSbZcmGjcrrI+hgOKpeullRoBtrdnhFoHzZAGaVLbELhz9g/iQyhL +X0J1yXhluy1LuemXCb4fSV5Xhsc/++sYkFd+hsDhd+xnbifr94B65rHdeMny7xsQ +PuJviYtWjWnX8BseNdZBxhqAHxW+Dq7Jh9/ogKKFIN4yOvjMEnLrQR4rKik/9+Hr +KZmttI15CpmOD0ofROl0txfLlyF6fdVspf3RU7UhjApTTQrpTUBSCzVfQAkJH222 +BJx18u4yidj/o1s3k2nwJUzsKqce4ikz7wf0YYyRqbv5ibqy3ZgIkb939rs794r3 +HNdrF9P6YhIuu9O/eKPrHssAcG6HP57r/S0yd/Ixr1zcFacs2a7n+/gBSslF84fc +x8wU/n99RpQIrCVqGAJJtaq9T8UaBLisoWpUARkF9FXgCJhn9exhCez8gZuId1N6 +0UhMj+K3DQYEvAVuDwqhVgexE0GQSf0ScPYBV63WLaKhBM/RKTj1aHZYm10eDyx3 +9vDP2N/F0iOLNKmulGd0SyGZfLvevvlctusULbs4VvsMfHBCQhsbPJhtYR8WMs5z +KiOe6+bRiQ0wB9KUCYxtOEnmB/29I0hHbMrA2lDoXwYIcuHK/ZH8KfwmQP8deBYj +H8JkQQS2PEC3CCemfSZK/Vev7rrjk0UHZFxfwKfoolunPdrTlx982ncADTA+4679 +TMcY5mLgnXQPkACqwjLe3NGP18PCCL/RvX4hCXkyjxoSQ5eRQTO91C47qW0GI9Ha +fl9FJ9UXnA7fLNFmy+3s48Nrqw26cQSkkqRxVWkgNXL9rVSoz0TDnaFalE0FYl6Y +1iXF1s/175TALFOHC58TD2PFl9VbikZ8DijeZpZ03yqysCdtTE9UctktrlhP02Nj +k8I0V2Y7OJA2qamV5n3ohIdoc5tEaNlpHxwbnVhEd3LoKMEaEb1cQLfQWLlYkZ9b +MJQz+va+KlmLQ8zjBEUbQ37XtfTT3F1lrmvRktL3to/fxlwAwws3KDMz3QXLPGIN +C1RC6p9s6fLvx6t8XM8YVTUc93KPw9UbwAlvROgGYkTECxDiw7Gc3nM3XVG8tj84 +G3XZJt9PGutjnOFJEeTL7OM6seIAi5K7c/sFeIHnrCEbI8GPi5xSuwnaciO/geZ0 +GGMfhJtdBpJyqoRQ9I8qlAWPQl/eRQWyviY93MTvg8uqtGcvXOL5s5wf+ZKPQE+Z +35pe/cXbktyoQRNk9LsKZYfczzkwvp46hmLWLm8Xitl3OuKNjwjrHv2vZyId//+4 +IiuTUR0Sx2uFTbcYlmTiJQbsRWdjK7EjAgMBAAEwDQYJKoZIhvcNAQELBQADggQC +ALp/dV9f5ql6slOo1AJgISnOpeOViusi0FTzdhsipL0r/qAO9EaKxLTuWMrA3Hoc +JjCZhe3lrjojgXZbtOhQM28ZUqYDgscTzk+Xr9dCbigP8s/m6/npZUAukkSHrPej +ZYSmRh7GPCOamBPY886gIAbTauzbP9eSXAGn4cHZum8bQQ//bYDd32kbRTbx5B1y +llc9ioDjrrSRjohASOYzDeetP6rTwZbyRHO7UVbOdbXpLfCnn2jauxeetMGigRW+ +KEP3LCA1lBczmVIzi3tyEiffiCkRky5ViutjVhTpy1jjplLkIQRI/AmgMIqMz9+y +bFzTlgpZJnC1+tAazwbpMPiiRVJjQ8mN7hM1xG38+RZP91xWFhofF2z2LiDW7FcP ++jQcp7UY+n0WVHE+zZdw+Ll96meDUHRNp8WQqFFQUGHJMQZjeo08uev1MTz6vkoe +LQImy337VCEWegZyNP0anDaf0Eq/34Z0D/zfvzJqQa4kZ6FK98jNoWqbxWnbcpS5 +hROrICV3si+kQOzpD2iyqPd4UPVbMGtnSvDKVxgNVJq95DMknFFKb5mSPgULqNGf +qNRUKLCLvgr/ZHaqdnzwIz/BjZFPBDcsMJAebWBBiJ21ewobmOUVWEfY/RHQD13s +bGX9PLFKpHp5velNTTl7mzB2ERzF31FbfntEHiVENfNxGTvUel7bOjyFVA+x2R2r +aYgEoS43d42XqiQXr1Rxn/8ddOnzfch56QhZX9wO2Ldb+u5MB89R++dbfNDVhfkI +nIFqg/cVzfxNpac5a7LM8umQt+rlXjqgqR3ljS+AmzCK8P/VwqYOg3uA7PR7iPSt +aQGBNZQUDI5Qk6U5F1sG4HA8+W5eCYmEI3QSQoIieLyqZNNR9MaWijMZVrshb73d +yQtpDiwXXmcSZAgh/S5bSRRun0eGpJlLBqVQIDCkx/sy1bZbdIJMetDiK5l6Z2l6 +PtBOZevTrUGDceHDx2k2A6zkC80m1wA2iCY2Iv7U1U95WogQVZgN5uNJyPu1s7hc +y6NXgKgGNDJXcArfeNTR+cwn7xcuOCbmMv99p/hEs1IATKCvdmqjmcKnc8j9nPpA +yEgPg+gDPyt+Orw7bEOvK8qjKacq0sIikJj7fjN5w225Vpa9bfVXz3kDd+aFF9J7 +WmdtA7LM4E+BVtdU980xx73P1BmfmRuRaSibCSd3KN5Pyyo4TSko3k+k1OQJoqTK +3Ybk/TuVGlp0nzuvMtAlemfD3saTDoprHnmJTAyGkc+1vbM9bMAmdINJYsxRgzrn +CLsXZxfC+pqvhle4RKY/r48hhb2IW/8br3g7qpB0/zrzGEBpTzWmRYD/mXuVo1Eb +4CbMRkHcSspUosEU2UQ2uusp -----END CERTIFICATE-----
diff --git a/net/data/ssl/scripts/generate-test-certs.sh b/net/data/ssl/scripts/generate-test-certs.sh index b2481ad..adf97ba9 100755 --- a/net/data/ssl/scripts/generate-test-certs.sh +++ b/net/data/ssl/scripts/generate-test-certs.sh
@@ -164,9 +164,9 @@ -out ../certificates/reject_intranet_hosts.pem ## Leaf certificate with a large key; Apple's certificate verifier rejects with -## a fatal error if the key is bigger than 4096 bits. +## a fatal error if the key is bigger than 8192 bits. try openssl req -x509 -days 3650 \ - -config ../scripts/ee.cnf -newkey rsa:4104 -text \ + -config ../scripts/ee.cnf -newkey rsa:8200 -text \ -sha256 \ -out ../certificates/large_key.pem
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc index b149ac0..4be580b 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc +++ b/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc
@@ -99,7 +99,6 @@ void TearDown() override { store_ = NULL; - pool_owner_->pool()->Shutdown(); } protected:
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc index fd140ea..92965ee5 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc +++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -196,7 +196,6 @@ void TearDown() override { DestroyStore(); - pool_owner_->pool()->Shutdown(); } protected:
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index a8c5ac4..7389d085 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -6,11 +6,13 @@ #include <utility> +#include "base/atomic_sequence_num.h" #include "base/compiler_specific.h" #include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" #include "net/http/http_auth_handler_factory.h" @@ -34,9 +36,12 @@ namespace { +base::StaticAtomicSequenceNumber g_next_shard_id; + ClientSocketPoolManager* CreateSocketPoolManager( HttpNetworkSession::SocketPoolType pool_type, - const HttpNetworkSession::Params& params) { + const HttpNetworkSession::Params& params, + const std::string& ssl_session_cache_shard) { // TODO(yutak): Differentiate WebSocket pool manager and allow more // simultaneous connections for WebSockets. return new ClientSocketPoolManagerImpl( @@ -45,7 +50,7 @@ : ClientSocketFactory::GetDefaultFactory(), params.host_resolver, params.cert_verifier, params.channel_id_service, params.transport_security_state, params.cert_transparency_verifier, - params.cert_policy_enforcer, params.ssl_session_cache_shard, + params.cert_policy_enforcer, ssl_session_cache_shard, params.ssl_config_service, pool_type); } @@ -134,10 +139,6 @@ http_auth_handler_factory_(params.http_auth_handler_factory), proxy_service_(params.proxy_service), ssl_config_service_(params.ssl_config_service), - normal_socket_pool_manager_( - CreateSocketPoolManager(NORMAL_SOCKET_POOL, params)), - websocket_socket_pool_manager_( - CreateSocketPoolManager(WEBSOCKET_SOCKET_POOL, params)), quic_stream_factory_( params.host_resolver, params.client_socket_factory @@ -194,6 +195,13 @@ DCHECK(ssl_config_service_.get()); CHECK(http_server_properties_); + const std::string ssl_session_cache_shard = + "http_network_session/" + base::IntToString(g_next_shard_id.GetNext()); + normal_socket_pool_manager_.reset(CreateSocketPoolManager( + NORMAL_SOCKET_POOL, params, ssl_session_cache_shard)); + websocket_socket_pool_manager_.reset(CreateSocketPoolManager( + WEBSOCKET_SOCKET_POOL, params, ssl_session_cache_shard)); + for (int i = ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION; i <= ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION; ++i) { enabled_protocols_[i - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] = false;
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index f250cca..d9194e1 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -71,7 +71,6 @@ TransportSecurityState* transport_security_state; CTVerifier* cert_transparency_verifier; ProxyService* proxy_service; - std::string ssl_session_cache_shard; SSLConfigService* ssl_config_service; HttpAuthHandlerFactory* http_auth_handler_factory; NetworkDelegate* network_delegate;
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc index 551ad6d..f31de156 100644 --- a/net/spdy/spdy_stream.cc +++ b/net/spdy/spdy_stream.cc
@@ -4,6 +4,8 @@ #include "net/spdy/spdy_stream.h" +#include <limits> + #include "base/bind.h" #include "base/compiler_specific.h" #include "base/location.h" @@ -36,8 +38,8 @@ scoped_ptr<base::Value> NetLogSpdyStreamWindowUpdateCallback( SpdyStreamId stream_id, - int32 delta, - int32 window_size, + int32_t delta, + int32_t window_size, NetLogCaptureMode /* capture_mode */) { scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->SetInteger("stream_id", stream_id); @@ -87,8 +89,8 @@ const base::WeakPtr<SpdySession>& session, const GURL& url, RequestPriority priority, - int32 initial_send_window_size, - int32 max_recv_window_size, + int32_t initial_send_window_size, + int32_t max_recv_window_size, const BoundNetLog& net_log) : type_(type), stream_id_(0), @@ -220,7 +222,7 @@ Cancel(); } -void SpdyStream::AdjustSendWindowSize(int32 delta_window_size) { +void SpdyStream::AdjustSendWindowSize(int32_t delta_window_size) { DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); if (IsClosed()) @@ -228,10 +230,12 @@ // Check for wraparound. if (send_window_size_ > 0) { - DCHECK_LE(delta_window_size, kint32max - send_window_size_); + DCHECK_LE(delta_window_size, + std::numeric_limits<int32_t>::max() - send_window_size_); } if (send_window_size_ < 0) { - DCHECK_GE(delta_window_size, kint32min - send_window_size_); + DCHECK_GE(delta_window_size, + std::numeric_limits<int32_t>::min() - send_window_size_); } send_window_size_ += delta_window_size; PossiblyResumeIfSendStalled(); @@ -249,13 +253,13 @@ // error and we'll be tearing down the stream soon.) size_t remaining_payload_bytes = std::min(consume_size, frame_payload_size); DCHECK_GT(remaining_payload_bytes, 0u); - IncreaseSendWindowSize(static_cast<int32>(remaining_payload_bytes)); + IncreaseSendWindowSize(static_cast<int32_t>(remaining_payload_bytes)); } // For consumed bytes, the send window is increased when we receive // a WINDOW_UPDATE frame. } -void SpdyStream::IncreaseSendWindowSize(int32 delta_window_size) { +void SpdyStream::IncreaseSendWindowSize(int32_t delta_window_size) { DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); DCHECK_GE(delta_window_size, 1); @@ -265,7 +269,8 @@ if (send_window_size_ > 0) { // Check for overflow. - int32 max_delta_window_size = kint32max - send_window_size_; + int32_t max_delta_window_size = + std::numeric_limits<int32_t>::max() - send_window_size_; if (delta_window_size > max_delta_window_size) { std::string desc = base::StringPrintf( "Received WINDOW_UPDATE [delta: %d] for stream %d overflows " @@ -286,7 +291,7 @@ PossiblyResumeIfSendStalled(); } -void SpdyStream::DecreaseSendWindowSize(int32 delta_window_size) { +void SpdyStream::DecreaseSendWindowSize(int32_t delta_window_size) { DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); if (IsClosed()) @@ -314,11 +319,12 @@ SpdyBuffer::ConsumeSource consume_source) { DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); DCHECK_GE(consume_size, 1u); - DCHECK_LE(consume_size, static_cast<size_t>(kint32max)); - IncreaseRecvWindowSize(static_cast<int32>(consume_size)); + DCHECK_LE(consume_size, + static_cast<size_t>(std::numeric_limits<int32_t>::max())); + IncreaseRecvWindowSize(static_cast<int32_t>(consume_size)); } -void SpdyStream::IncreaseRecvWindowSize(int32 delta_window_size) { +void SpdyStream::IncreaseRecvWindowSize(int32_t delta_window_size) { DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); // By the time a read is processed by the delegate, this stream may @@ -330,7 +336,8 @@ DCHECK_GE(recv_window_size_, unacked_recv_window_bytes_); DCHECK_GE(delta_window_size, 1); // Check for overflow. - DCHECK_LE(delta_window_size, kint32max - recv_window_size_); + DCHECK_LE(delta_window_size, + std::numeric_limits<int32_t>::max() - recv_window_size_); recv_window_size_ += delta_window_size; net_log_.AddEvent( @@ -341,12 +348,12 @@ unacked_recv_window_bytes_ += delta_window_size; if (unacked_recv_window_bytes_ > max_recv_window_size_ / 2) { session_->SendStreamWindowUpdate( - stream_id_, static_cast<uint32>(unacked_recv_window_bytes_)); + stream_id_, static_cast<uint32_t>(unacked_recv_window_bytes_)); unacked_recv_window_bytes_ = 0; } } -void SpdyStream::DecreaseRecvWindowSize(int32 delta_window_size) { +void SpdyStream::DecreaseRecvWindowSize(int32_t delta_window_size) { DCHECK(session_->IsStreamActive(stream_id_)); DCHECK_GE(session_->flow_control_state(), SpdySession::FLOW_CONTROL_STREAM); DCHECK_GE(delta_window_size, 1); @@ -530,7 +537,7 @@ if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) { base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); // May close the stream. - DecreaseRecvWindowSize(static_cast<int32>(length)); + DecreaseRecvWindowSize(static_cast<int32_t>(length)); if (!weak_this) return; buffer->AddConsumeCallback( @@ -553,10 +560,10 @@ // |recv_window_size_| does not change. base::WeakPtr<SpdyStream> weak_this = GetWeakPtr(); // May close the stream. - DecreaseRecvWindowSize(static_cast<int32>(len)); + DecreaseRecvWindowSize(static_cast<int32_t>(len)); if (!weak_this) return; - IncreaseRecvWindowSize(static_cast<int32>(len)); + IncreaseRecvWindowSize(static_cast<int32_t>(len)); } } @@ -854,7 +861,7 @@ // Send window size is based on payload size, so nothing to do if this is // just a FIN with no payload. if (payload_size != 0) { - DecreaseSendWindowSize(static_cast<int32>(payload_size)); + DecreaseSendWindowSize(static_cast<int32_t>(payload_size)); // This currently isn't strictly needed, since write frames are // discarded only if the stream is about to be closed. But have it // here anyway just in case this changes.
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h index faf06e3..b356aa1 100644 --- a/net/spdy/spdy_stream.h +++ b/net/spdy/spdy_stream.h
@@ -11,7 +11,6 @@ #include <string> #include <vector> -#include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" @@ -169,8 +168,8 @@ const base::WeakPtr<SpdySession>& session, const GURL& url, RequestPriority priority, - int32 initial_send_window_size, - int32 max_recv_window_size, + int32_t initial_send_window_size, + int32_t max_recv_window_size, const BoundNetLog& net_log); ~SpdyStream(); @@ -198,9 +197,9 @@ RequestPriority priority() const { return priority_; } - int32 send_window_size() const { return send_window_size_; } + int32_t send_window_size() const { return send_window_size_; } - int32 recv_window_size() const { return recv_window_size_; } + int32_t recv_window_size() const { return recv_window_size_; } bool send_stalled_by_flow_control() const { return send_stalled_by_flow_control_; @@ -220,7 +219,7 @@ // closed. // // If stream flow control is turned off, this must not be called. - void AdjustSendWindowSize(int32 delta_window_size); + void AdjustSendWindowSize(int32_t delta_window_size); // Called when bytes are consumed from a SpdyBuffer for a DATA frame // that is to be written or is being written. Increases the send @@ -241,7 +240,7 @@ // nothing if the stream is already closed. // // If stream flow control is turned off, this must not be called. - void IncreaseSendWindowSize(int32 delta_window_size); + void IncreaseSendWindowSize(int32_t delta_window_size); // If stream flow control is turned on, called by the session to // decrease this stream's send window size by |delta_window_size|, @@ -250,7 +249,7 @@ // to go negative. Does nothing if the stream is already closed. // // If stream flow control is turned off, this must not be called. - void DecreaseSendWindowSize(int32 delta_window_size); + void DecreaseSendWindowSize(int32_t delta_window_size); // Called when bytes are consumed by the delegate from a SpdyBuffer // containing received data. Increases the receive window size @@ -267,7 +266,7 @@ // stream is not active. // // If stream flow control is turned off, this must not be called. - void IncreaseRecvWindowSize(int32 delta_window_size); + void IncreaseRecvWindowSize(int32_t delta_window_size); // Called by OnDataReceived or OnPaddingConsumed (which are in turn called by // the session) to decrease this stream's receive window size by @@ -276,7 +275,7 @@ // // If stream flow control is turned off or the stream is not active, // this must not be called. - void DecreaseRecvWindowSize(int32 delta_window_size); + void DecreaseRecvWindowSize(int32_t delta_window_size); int GetPeerAddress(IPEndPoint* address) const; int GetLocalAddress(IPEndPoint* address) const; @@ -425,7 +424,7 @@ void AddRawReceivedBytes(size_t received_bytes); void AddRawSentBytes(size_t sent_bytes); - int64 raw_received_bytes() const { return raw_received_bytes_; } + int64_t raw_received_bytes() const { return raw_received_bytes_; } int64_t raw_sent_bytes() const { return raw_sent_bytes_; } bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const; @@ -509,22 +508,22 @@ bool send_stalled_by_flow_control_; // Current send window size. - int32 send_window_size_; + int32_t send_window_size_; // Maximum receive window size. Each time a WINDOW_UPDATE is sent, it // restores the receive window size to this value. - int32 max_recv_window_size_; + int32_t max_recv_window_size_; // Sum of |session_unacked_recv_window_bytes_| and current receive window // size. // TODO(bnc): Rename or change semantics so that |window_size_| is actual // window size. - int32 recv_window_size_; + int32_t recv_window_size_; // When bytes are consumed, SpdyIOBuffer destructor calls back to SpdySession, // and this member keeps count of them until the corresponding WINDOW_UPDATEs // are sent. - int32 unacked_recv_window_bytes_; + int32_t unacked_recv_window_bytes_; const base::WeakPtr<SpdySession> session_; @@ -570,7 +569,7 @@ // Number of bytes that have been received on this stream, including frame // overhead and headers. - int64 raw_received_bytes_; + int64_t raw_received_bytes_; // Number of bytes that have been sent on this stream, including frame // overhead and headers. int64_t raw_sent_bytes_;
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py index 7919f87..10ade37 100755 --- a/net/tools/testserver/testserver.py +++ b/net/tools/testserver/testserver.py
@@ -1629,6 +1629,12 @@ # a range? range_response = False range_header = self.headers.getheader('range') + + if fail_precondition and self.headers.getheader('If-Range'): + # Failing a precondition for an If-Range just means that we are going to + # return the entire entity ignoring the Range header. + respond_to_range = False + if range_header and respond_to_range: mo = re.match("bytes=(\d*)-(\d*)", range_header) if mo.group(1): @@ -1641,13 +1647,6 @@ if last_byte < first_byte: return False - if (fail_precondition and - (self.headers.getheader('If-Modified-Since') or - self.headers.getheader('If-Match'))): - self.send_response(412) - self.end_headers() - return True - if range_response: self.send_response(206) self.send_header('Content-Range',
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index 91e3991..83ea66f 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -403,8 +403,6 @@ http_network_session_params_.quic_packet_loss_threshold; network_session_params.quic_connection_options = http_network_session_params_.quic_connection_options; - network_session_params.ssl_session_cache_shard = - http_network_session_params_.ssl_session_cache_shard; storage->set_http_network_session( make_scoped_ptr(new HttpNetworkSession(network_session_params)));
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h index d17c8665..81962e1 100644 --- a/net/url_request/url_request_context_builder.h +++ b/net/url_request/url_request_context_builder.h
@@ -92,7 +92,6 @@ int quic_max_number_of_lossy_connections; float quic_packet_loss_threshold; QuicTagVector quic_connection_options; - std::string ssl_session_cache_shard; }; URLRequestContextBuilder(); @@ -197,11 +196,6 @@ quic_connection_options; } - void set_ssl_session_cache_shard(const std::string& ssl_session_cache_shard) { - http_network_session_params_.ssl_session_cache_shard = - ssl_session_cache_shard; - } - void set_quic_store_server_configs_in_properties( bool quic_store_server_configs_in_properties) { http_network_session_params_.quic_store_server_configs_in_properties =
diff --git a/net/url_request/url_request_context_builder_unittest.cc b/net/url_request/url_request_context_builder_unittest.cc index e0703d78..8c280d35 100644 --- a/net/url_request/url_request_context_builder_unittest.cc +++ b/net/url_request/url_request_context_builder_unittest.cc
@@ -111,14 +111,6 @@ "Bogus", HttpAuth::AUTH_SERVER, gurl, BoundNetLog(), &handler)); } -TEST_F(URLRequestContextBuilderTest, set_ssl_session_cache_shard) { - const char kTestShard[] = "test_shard"; - builder_.set_ssl_session_cache_shard(kTestShard); - scoped_ptr<URLRequestContext> context(builder_.Build()); - EXPECT_EQ(kTestShard, - context->GetNetworkSessionParams()->ssl_session_cache_shard); -} - } // namespace } // namespace net
diff --git a/net/url_request/url_request_simple_job_unittest.cc b/net/url_request/url_request_simple_job_unittest.cc index 1286977b..08c08fb 100644 --- a/net/url_request/url_request_simple_job_unittest.cc +++ b/net/url_request/url_request_simple_job_unittest.cc
@@ -6,7 +6,7 @@ #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/test/sequenced_worker_pool_owner.h" #include "base/threading/worker_pool.h" #include "net/base/request_priority.h" #include "net/url_request/url_request_job.h" @@ -114,11 +114,12 @@ class URLRequestSimpleJobTest : public ::testing::Test { public: URLRequestSimpleJobTest() - : worker_pool_( - new base::SequencedWorkerPool(1, "URLRequestSimpleJobTest")), - task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool_->GetSequenceToken(), - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), + : worker_pool_owner_(1, "URLRequestSimpleJobTest"), + task_runner_(worker_pool_owner_.pool() + ->GetSequencedTaskRunnerWithShutdownBehavior( + worker_pool_owner_.pool() + ->GetSequenceToken(), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), context_(true) { job_factory_.SetProtocolHandler( "data", make_scoped_ptr(new SimpleJobProtocolHandler(task_runner_))); @@ -129,8 +130,6 @@ context_.CreateRequest(GURL("data:test"), DEFAULT_PRIORITY, &delegate_); } - ~URLRequestSimpleJobTest() override { worker_pool_->Shutdown(); } - void StartRequest(const HttpRequestHeaders* headers) { if (headers) request_->SetExtraRequestHeaders(*headers); @@ -141,10 +140,8 @@ EXPECT_FALSE(request_->is_pending()); } - void TearDown() override { worker_pool_->Shutdown(); } - protected: - scoped_refptr<base::SequencedWorkerPool> worker_pool_; + base::SequencedWorkerPoolOwner worker_pool_owner_; scoped_refptr<base::SequencedTaskRunner> task_runner_; TestURLRequestContext context_; URLRequestJobFactoryImpl job_factory_;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index ef1b0a09..939a6c61 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -8364,7 +8364,6 @@ default_context_.http_auth_handler_factory(); params.network_delegate = &default_network_delegate_; params.http_server_properties = default_context_.http_server_properties(); - params.ssl_session_cache_shard = "alternate"; HttpNetworkSession network_session(params); scoped_ptr<HttpCache> cache(new HttpCache(
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn index dc76515..818736e 100644 --- a/ppapi/BUILD.gn +++ b/ppapi/BUILD.gn
@@ -70,6 +70,18 @@ ] } +shared_library("blink_test_plugin") { + sources = [ + "tests/blink_test_plugin.cc", + ] + + deps = [ + "//build/config/sanitizers:deps", + "//ppapi/cpp", + "//ppapi/shared_impl", + ] +} + test("ppapi_unittests") { sources = [ "host/resource_message_filter_unittest.cc",
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index 830933ef..e0c21fb 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi
@@ -101,6 +101,25 @@ ], }, { + # GN version: //ppapi:blink_test_plugin + 'target_name': 'blink_test_plugin', + 'type': 'loadable_module', + 'sources': [ + 'tests/blink_test_plugin.cc', + ], + 'dependencies': [ + 'ppapi.gyp:ppapi_cpp', + 'ppapi_internal.gyp:ppapi_shared', + ], + 'conditions': [ + ['OS=="mac"', { + 'mac_bundle': 1, + 'product_name': 'blink_test_plugin', + 'product_extension': 'plugin', + }], + ], + }, + { # GN version: //ppapi/proxy:test_support # //ppapi/shared_impl:test_support 'target_name': 'ppapi_unittest_shared',
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc index 854bf51d..3dadacb 100644 --- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc +++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
@@ -48,7 +48,7 @@ if ((width < 0) || (height < 0)) return PP_ERROR_BADARGUMENT; - gles2_impl()->ResizeCHROMIUM(width, height, 1.f); + gles2_impl()->ResizeCHROMIUM(width, height, 1.f, true); // TODO(alokp): Check if resize succeeded and return appropriate error code. return PP_OK; }
diff --git a/ppapi/tests/blink_test_plugin.cc b/ppapi/tests/blink_test_plugin.cc new file mode 100644 index 0000000..91de50b --- /dev/null +++ b/ppapi/tests/blink_test_plugin.cc
@@ -0,0 +1,179 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <sstream> +#include <utility> + +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" + +namespace { + +void DummyCompletionCallback(void*, int32_t) {} + +// This is a simple C++ Pepper plugin for Blink layout tests. +// +// Layout tests can instantiate this plugin by requesting the mime type +// application/x-blink-test-plugin. When possible, tests should use the +// startAfterLoadAndFinish() helper in resources/plugin.js to perform work +// after the plugin has loaded. +// +// The plugin also exposes several other features for testing convenience: +// - On first paint, the plugin posts a 'loaded' message to its owner element. +// - On subsequent paints, the plugin posts a 'painted' message instead. +// - Keyboard and mouse input events are logged to the console. +class BlinkTestInstance : public pp::Instance { + public: + explicit BlinkTestInstance(PP_Instance instance) + : pp::Instance(instance), first_paint_(true) {} + ~BlinkTestInstance() override {} + + bool Init(uint32_t argc, const char* argn[], const char* argv[]) { + return RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_MOUSE | + PP_INPUTEVENT_CLASS_KEYBOARD) == PP_OK; + } + + void DidChangeView(const pp::View& view) override { + view_ = view; + device_context_ = pp::Graphics2D(this, view_.GetRect().size(), true); + if (!BindGraphics(device_context_)) + return; + + // Since we draw a static image, we only need to make a new frame when + // the device is initialized or the view size changes. + Paint(); + } + + void DidChangeFocus(bool has_focus) override { + LogMessage("DidChangeFocus(", has_focus, ")"); + } + + bool HandleInputEvent(const pp::InputEvent& event) override { + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + LogMouseEvent("Down", event); + break; + case PP_INPUTEVENT_TYPE_MOUSEUP: + LogMouseEvent("Up", event); + break; + case PP_INPUTEVENT_TYPE_KEYDOWN: + LogKeyboardEvent("Down", event); + break; + case PP_INPUTEVENT_TYPE_KEYUP: + LogKeyboardEvent("Up", event); + break; + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + case PP_INPUTEVENT_TYPE_MOUSEENTER: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: + case PP_INPUTEVENT_TYPE_CHAR: + // Just swallow these events without any logging. + return true; + default: + LogMessage("Unexpected input event with type = ", event.GetType()); + return false; + } + return true; + } + + private: + void Paint() { + pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, + view_.GetRect().size(), true); + if (image.is_null()) + return; + + // Draw blue and green checkerboard pattern to show "interesting" keyframe. + const int kSquareSizePixels = 8; + for (int y = 0; y < view_.GetRect().size().height(); ++y) { + for (int x = 0; x < view_.GetRect().size().width(); ++x) { + int x_square = x / kSquareSizePixels; + int y_square = y / kSquareSizePixels; + uint32_t color = ((x_square + y_square) % 2) ? 0xFF0000FF : 0xFF00FF00; + *image.GetAddr32(pp::Point(x, y)) = color; + } + } + + device_context_.ReplaceContents(&image); + device_context_.Flush( + pp::CompletionCallback(&DummyCompletionCallback, nullptr)); + + // TODO(dcheng): In theory, this should wait for the flush to complete + // before claiming that it's painted. In practice, this is difficult: when + // running layout tests, a frame is typically only generated at the end of + // the layout test. Sending the completion message in the callback results + // in a deadlock: the test wants to wait for the plugin to paint, but the + // plugin won't paint until the test completes. This seems to be Good + // Enough™ for now. + if (first_paint_) { + first_paint_ = false; + PostMessage(pp::Var("loaded")); + } else { + PostMessage(pp::Var("painted")); + } + } + + void LogMouseEvent(const std::string& type, const pp::InputEvent& event) { + pp::MouseInputEvent mouse_event(event); + pp::Point mouse_position = mouse_event.GetPosition(); + LogMessage("Mouse", type, " at (", mouse_position.x(), ",", + mouse_position.y(), ")"); + } + + void LogKeyboardEvent(const std::string& type, const pp::InputEvent& event) { + pp::KeyboardInputEvent keyboard_event(event); + LogMessage("Key", type, " '", keyboard_event.GetCode().AsString(), "'"); + } + + // Template magic to cover the lack of base::StringPrintf. + template <typename... Args> + void LogMessage(const Args&... args) { + std::ostringstream ss; + ss << std::boolalpha; + LogMessageHelper(&ss, args...); + } + + template <typename Arg, typename... Args> + void LogMessageHelper(std::ostringstream* os, + const Arg& arg, + const Args&... args) { + *os << arg; + LogMessageHelper(os, args...); + } + + template <typename Arg> + void LogMessageHelper(std::ostringstream* os, const Arg& arg) { + *os << arg; + LogToConsoleWithSource(PP_LOGLEVEL_LOG, pp::Var("Blink Test Plugin"), + pp::Var(os->str())); + } + + bool first_paint_; + pp::View view_; + pp::Graphics2D device_context_; +}; + +class BlinkTestModule : public pp::Module { + public: + BlinkTestModule() {} + virtual ~BlinkTestModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new BlinkTestInstance(instance); + } +}; + +} // namespace + +namespace pp { + +Module* CreateModule() { + return new BlinkTestModule(); +} + +} // namespace pp
diff --git a/printing/printing_context_win_unittest.cc b/printing/printing_context_win_unittest.cc index aab83f3..6b2b20f 100644 --- a/printing/printing_context_win_unittest.cc +++ b/printing/printing_context_win_unittest.cc
@@ -118,13 +118,13 @@ memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDriverOffset, info_2.get()->pDriverName, driver_size); - dev_names->wDeviceOffset = - dev_names->wDriverOffset + driver_size / sizeof(wchar_t); + dev_names->wDeviceOffset = base::checked_cast<WORD>( + dev_names->wDriverOffset + driver_size / sizeof(wchar_t)); memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDeviceOffset, info_2.get()->pPrinterName, printer_size); - dev_names->wOutputOffset = - dev_names->wDeviceOffset + printer_size / sizeof(wchar_t); + dev_names->wOutputOffset = base::checked_cast<WORD>( + dev_names->wDeviceOffset + printer_size / sizeof(wchar_t)); memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wOutputOffset, info_2.get()->pPortName, port_size);
diff --git a/remoting/android/java/src/org/chromium/chromoting/Capabilities.java b/remoting/android/java/src/org/chromium/chromoting/Capabilities.java index cff3d9e8..294a242 100644 --- a/remoting/android/java/src/org/chromium/chromoting/Capabilities.java +++ b/remoting/android/java/src/org/chromium/chromoting/Capabilities.java
@@ -12,4 +12,5 @@ */ public class Capabilities { public static final String CAST_CAPABILITY = "casting"; + public static final String TOUCH_CAPABILITY = "touchEvents"; }
diff --git a/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java b/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java index 939817d..e332e839 100644 --- a/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java +++ b/remoting/android/java/src/org/chromium/chromoting/CapabilityManager.java
@@ -27,6 +27,27 @@ * different capabilities at different stages of the application. */ public class CapabilityManager { + /** Used to allow objects to receive notifications when the host capabilites are received. */ + public interface CapabilitiesChangedListener { + void onCapabilitiesChanged(List<String> newCapabilities); + } + + /** Tracks whether the remote host supports a capability. */ + public enum HostCapability { + UNKNOWN, + SUPPORTED, + UNSUPPORTED; + + public boolean isSet() { + return this != UNKNOWN; + } + + public boolean isSupported() { + assert isSet(); + return this == SUPPORTED; + } + } + private static final String TAG = "Chromoting"; /** Lazily-initialized singleton object that can be used from different Activities. */ @@ -44,11 +65,17 @@ /** List of extensions to the client based on capabilities negotiated with the host. */ private List<ClientExtension> mClientExtensions; + /** Maintains a list of listeners to notify when host capabilities are received. */ + private List<CapabilitiesChangedListener> mCapabilitiesChangedListeners; + private CapabilityManager() { mLocalCapabilities = new ArrayList<String>(); mClientExtensions = new ArrayList<ClientExtension>(); mLocalCapabilities.add(Capabilities.CAST_CAPABILITY); + mLocalCapabilities.add(Capabilities.TOUCH_CAPABILITY); + + mCapabilitiesChangedListeners = new ArrayList<CapabilitiesChangedListener>(); } /** @@ -64,6 +91,13 @@ } /** + * Cleans up host specific state when the connection has been terminated. + */ + public void onHostDisconnect() { + mNegotiatedCapabilities = null; + } + + /** * Returns a space-separated list (required by host) of the capabilities supported by * this client. */ @@ -72,6 +106,30 @@ } /** + * Registers the given listener object so it is notified when host capabilities are negotiated. + */ + public void addListener(CapabilitiesChangedListener listener) { + assert !mCapabilitiesChangedListeners.contains(listener); + mCapabilitiesChangedListeners.add(listener); + + // If we have already received the host capabilities before this listener was registered, + // then fire the event for this listener immediately. + if (mNegotiatedCapabilities != null) { + // Clone the capabilities list passed to the caller to prevent them from mutating it. + listener.onCapabilitiesChanged(new ArrayList<>(mNegotiatedCapabilities)); + } + } + + /** + * Removes the given listener object from the list of change listeners. + */ + public void removeListener(CapabilitiesChangedListener listener) { + assert mCapabilitiesChangedListeners.contains(listener); + + mCapabilitiesChangedListeners.remove(listener); + } + + /** * Returns the ActivityLifecycleListener associated with the specified capability, if * |capability| is enabled and such a listener exists. * @@ -97,10 +155,8 @@ } /** - * Receives the capabilities negotiated between client and host and creates the appropriate - * extension handlers. - * - * Currently only the CAST_CAPABILITY exists, so that is the only extension constructed. + * Receives the capabilities negotiated between client and host, creates the appropriate + * extension handlers, and notifies registered listeners of the change. */ public void setNegotiatedCapabilities(String capabilities) { mNegotiatedCapabilities = Arrays.asList(capabilities.split(" ")); @@ -108,6 +164,15 @@ if (isCapabilityEnabled(Capabilities.CAST_CAPABILITY)) { mClientExtensions.add(maybeCreateCastExtensionHandler()); } + + // Clone the list of listeners to prevent problems if the callback calls back into this + // object and removes itself from the list of listeners. + List<CapabilitiesChangedListener> listeners = + new ArrayList<>(mCapabilitiesChangedListeners); + for (CapabilitiesChangedListener listener : listeners) { + // Clone the capabilities list passed to the caller to prevent them from mutating it. + listener.onCapabilitiesChanged(new ArrayList<>(mNegotiatedCapabilities)); + } } /**
diff --git a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java index 64e0008..0f26ea7 100644 --- a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java +++ b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
@@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.Menu; +import android.view.MenuItem; import org.chromium.base.ApiCompatibilityUtils; @@ -27,10 +28,19 @@ int color = getColorAttribute(context, R.attr.colorControlNormal); int items = menu.size(); for (int i = 0; i < items; i++) { - Drawable icon = menu.getItem(i).getIcon(); - if (icon != null) { - icon.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } + ChromotingUtil.tintMenuIcon(menu.getItem(i), color); + } + } + + /** + * Sets a color filter on the specified MenuItem. + * @param menuItem MenuItem to tint. + * @param color Color to set on the menuItem. + */ + public static void tintMenuIcon(MenuItem menuItem, int color) { + Drawable icon = menuItem.getIcon(); + if (icon != null) { + icon.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN); } }
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java index e7b2628..99ef605d 100644 --- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java +++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -33,19 +33,36 @@ import org.chromium.chromoting.help.HelpSingleton; import org.chromium.chromoting.jni.JniInterface; +import java.util.List; import java.util.Set; import java.util.TreeSet; /** * A simple screen that does nothing except display a DesktopView and notify it of rotations. */ -public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibilityChangeListener { +public class Desktop + extends AppCompatActivity implements View.OnSystemUiVisibilityChangeListener, + CapabilityManager.CapabilitiesChangedListener { + /** Used to set/store the selected input mode. */ + public enum InputMode { + UNKNOWN, + TRACKPAD, + TOUCH; + + public boolean isSet() { + return this != UNKNOWN; + } + } + /** * Preference used for displaying an interestitial dialog only when the user first accesses the * Cardboard function. */ private static final String PREFERENCE_CARDBOARD_DIALOG_SEEN = "cardboard_dialog_seen"; + /** Preference used to track the last input mode selected by the user. */ + private static final String PREFERENCE_INPUT_MODE = "input_mode"; + /** The amount of time to wait to hide the Actionbar after user input is seen. */ private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 3000; @@ -69,6 +86,13 @@ /** The Toolbar instance backing our SupportActionBar. */ private Toolbar mToolbar; + /** Tracks the current input mode (e.g. trackpad/touch). */ + private InputMode mInputMode = InputMode.UNKNOWN; + + /** Indicates whether the remote host supports touch injection. */ + private CapabilityManager.HostCapability mHostTouchCapability = + CapabilityManager.HostCapability.UNKNOWN; + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { @@ -101,6 +125,8 @@ this, Capabilities.CAST_CAPABILITY); mActivityLifecycleListener.onActivityCreated(this, savedInstanceState); + mInputMode = getInitialInputModeValue(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { attachKeyboardVisibilityListener(); @@ -136,6 +162,7 @@ mActivityLifecycleListener.onActivityStarted(this); JniInterface.enableVideoChannel(true); mRemoteHostDesktop.attachRedrawCallback(); + CapabilityManager.getInstance().addListener(this); } @Override @@ -158,6 +185,7 @@ @Override protected void onStop() { + CapabilityManager.getInstance().removeListener(this); mActivityLifecycleListener.onActivityStopped(this); super.onStop(); if (mSwitchToCardboardDesktopActivity) { @@ -219,9 +247,80 @@ ChromotingUtil.tintMenuIcons(this, menu); + // Wait to set the input mode until after the default tinting has been applied. + setInputMode(mInputMode); + return super.onCreateOptionsMenu(menu); } + private InputMode getInitialInputModeValue() { + // Load the previously-selected input mode from Preferences. + // TODO(joedow): Evaluate and determine if we should use a different input mode based on + // a device characteristic such as screen size. + InputMode inputMode = InputMode.TRACKPAD; + String previousInputMode = + getPreferences(MODE_PRIVATE) + .getString(PREFERENCE_INPUT_MODE, inputMode.name()); + + try { + inputMode = InputMode.valueOf(previousInputMode); + } catch (IllegalArgumentException ex) { + // Invalid or unexpected value was found, just use the default mode. + } + + return inputMode; + } + + private void toggleInputMode() { + if (mInputMode == InputMode.TRACKPAD) { + setInputMode(InputMode.TOUCH); + } else if (mInputMode == InputMode.TOUCH) { + setInputMode(InputMode.TRACKPAD); + } + } + + private void setInputMode(InputMode inputMode) { + String titleText; + int inputModeItemColorId; + if (inputMode == InputMode.TRACKPAD) { + titleText = getString(R.string.select_trackpad_mode); + inputModeItemColorId = R.attr.colorControlNormal; + } else if (inputMode == InputMode.TOUCH) { + titleText = getString(R.string.select_touch_mode); + inputModeItemColorId = R.attr.colorControlActivated; + } else { + assert false : "Unreached"; + return; + } + + mInputMode = inputMode; + getPreferences(MODE_PRIVATE) + .edit() + .putString(PREFERENCE_INPUT_MODE, mInputMode.name()) + .apply(); + + Menu menu = mToolbar.getMenu(); + MenuItem inputModeMenuItem = menu.findItem(R.id.actionbar_input_mode); + if (inputModeMenuItem != null) { + inputModeMenuItem.setTitle(titleText); + int color = ChromotingUtil.getColorAttribute(this, inputModeItemColorId); + ChromotingUtil.tintMenuIcon(inputModeMenuItem, color); + } + + mRemoteHostDesktop.changeInputMode(mInputMode, mHostTouchCapability); + } + + @Override + public void onCapabilitiesChanged(List<String> newCapabilities) { + if (newCapabilities.contains(Capabilities.TOUCH_CAPABILITY)) { + mHostTouchCapability = CapabilityManager.HostCapability.SUPPORTED; + } else { + mHostTouchCapability = CapabilityManager.HostCapability.UNSUPPORTED; + } + + mRemoteHostDesktop.changeInputMode(mInputMode, mHostTouchCapability); + } + // Any time an onTouchListener is attached, a lint warning about filtering touch events is // generated. Since the function below is only used to listen to, not intercept, the events, // the lint warning can be safely suppressed. @@ -378,6 +477,10 @@ onCardboardItemSelected(); return true; } + if (id == R.id.actionbar_input_mode) { + toggleInputMode(); + return true; + } if (id == R.id.actionbar_keyboard) { ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, 0); return true;
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java index 466012b9..d2499be3 100644 --- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java +++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -159,9 +159,6 @@ mRenderData = new RenderData(); mInputHandler = new TouchInputHandler(this, context, mRenderData); - // TODO(joedow): Move this into a method which will choose the correct input strategy - // based on host support and current toggle setting in the UI. - mInputHandler.setInputStrategy(new TrackpadInputStrategy(this, mRenderData)); mRepaintPending = false; @@ -392,4 +389,32 @@ mInputAnimationRunning = enabled; } } + + /** Updates the current InputStrategy used by the TouchInputHandler. */ + public void changeInputMode( + Desktop.InputMode inputMode, CapabilityManager.HostCapability hostTouchCapability) { + // In order to set the correct input strategy, we need to know the current input mode and + // the host input capabilities. + if (!inputMode.isSet() || !hostTouchCapability.isSet()) { + return; + } + + switch (inputMode) { + case TRACKPAD: + mInputHandler.setInputStrategy(new TrackpadInputStrategy(this, mRenderData)); + break; + + case TOUCH: + if (hostTouchCapability.isSupported()) { + // TODO(joedow): Set the touch input strategy. + } else { + // TODO(joedow): Set the simulated touch input strategy. + } + break; + + default: + // Unreachable, but required by Google Java style and findbugs. + assert false : "Unreached"; + } + } }
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java index 69dbdba2..288fd78 100644 --- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java +++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -210,6 +210,7 @@ nativeDisconnect(); sConnectionListener = null; sConnected = false; + sCapabilityManager.onHostDisconnect(); // Drop the reference to free the Bitmap for GC. synchronized (sFrameLock) {
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn index b88785c6..4cf9908b 100644 --- a/remoting/protocol/BUILD.gn +++ b/remoting/protocol/BUILD.gn
@@ -112,6 +112,7 @@ "ppapi_module_stub.cc", "pseudotcp_adapter_unittest.cc", "quic_channel_factory_unittest.cc", + "session_config_unittest.cc", "ssl_hmac_channel_authenticator_unittest.cc", "third_party_authenticator_unittest.cc", "v2_authenticator_unittest.cc",
diff --git a/remoting/protocol/content_description.cc b/remoting/protocol/content_description.cc index ccc10b81..9d9f30a7 100644 --- a/remoting/protocol/content_description.cc +++ b/remoting/protocol/content_description.cc
@@ -32,14 +32,11 @@ const char kVideoTag[] = "video"; const char kAudioTag[] = "audio"; const char kVp9ExperimentTag[] = "vp9-experiment"; -const char kDeprecatedResolutionTag[] = "initial-resolution"; const char kQuicConfigTag[] = "quic-config"; const char kTransportAttr[] = "transport"; const char kVersionAttr[] = "version"; const char kCodecAttr[] = "codec"; -const char kDeprecatedWidthAttr[] = "width"; -const char kDeprecatedHeightAttr[] = "height"; const NameMapElement<ChannelConfig::TransportType> kTransports[] = { { ChannelConfig::TRANSPORT_STREAM, "stream" }, @@ -145,34 +142,27 @@ XmlElement* root = new XmlElement( QName(kChromotingXmlNamespace, kDescriptionTag), true); - if (config()->standard_ice()) { + if (config()->ice_supported()) { root->AddElement( new buzz::XmlElement(QName(kChromotingXmlNamespace, kStandardIceTag))); - } - for (const ChannelConfig& channel_config : config()->control_configs()) { - root->AddElement(FormatChannelConfig(channel_config, kControlTag)); - } + for (const auto& channel_config : config()->control_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kControlTag)); + } - for (const ChannelConfig& channel_config : config()->event_configs()) { - root->AddElement(FormatChannelConfig(channel_config, kEventTag)); - } + for (const auto& channel_config : config()->event_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kEventTag)); + } - for (const ChannelConfig& channel_config : config()->video_configs()) { - root->AddElement(FormatChannelConfig(channel_config, kVideoTag)); - } + for (const auto& channel_config : config()->video_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kVideoTag)); + } - for (const ChannelConfig& channel_config : config()->audio_configs()) { - root->AddElement(FormatChannelConfig(channel_config, kAudioTag)); + for (const auto& channel_config : config()->audio_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kAudioTag)); + } } - // Older endpoints require an initial-resolution tag, but otherwise ignore it. - XmlElement* resolution_tag = new XmlElement( - QName(kChromotingXmlNamespace, kDeprecatedResolutionTag)); - resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640"); - resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480"); - root->AddElement(resolution_tag); - if (authenticator_message_) { DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get())); root->AddElement(new XmlElement(*authenticator_message_)); @@ -222,7 +212,8 @@ // static scoped_ptr<ContentDescription> ContentDescription::ParseXml( - const XmlElement* element) { + const XmlElement* element, + bool webrtc_transport) { if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) { LOG(ERROR) << "Invalid description: " << element->Str(); return nullptr; @@ -230,19 +221,21 @@ scoped_ptr<CandidateSessionConfig> config( CandidateSessionConfig::CreateEmpty()); - config->set_standard_ice( - element->FirstNamed(QName(kChromotingXmlNamespace, kStandardIceTag)) != - nullptr); + config->set_webrtc_supported(webrtc_transport); - if (!ParseChannelConfigs(element, kControlTag, false, false, - config->mutable_control_configs()) || - !ParseChannelConfigs(element, kEventTag, false, false, - config->mutable_event_configs()) || - !ParseChannelConfigs(element, kVideoTag, true, false, - config->mutable_video_configs()) || - !ParseChannelConfigs(element, kAudioTag, true, true, - config->mutable_audio_configs())) { - return nullptr; + if (element->FirstNamed(QName(kChromotingXmlNamespace, kStandardIceTag)) != + nullptr) { + config->set_ice_supported(true); + if (!ParseChannelConfigs(element, kControlTag, false, false, + config->mutable_control_configs()) || + !ParseChannelConfigs(element, kEventTag, false, false, + config->mutable_event_configs()) || + !ParseChannelConfigs(element, kVideoTag, true, false, + config->mutable_video_configs()) || + !ParseChannelConfigs(element, kAudioTag, true, true, + config->mutable_audio_configs())) { + return nullptr; + } } // Check if VP9 experiment is enabled.
diff --git a/remoting/protocol/content_description.h b/remoting/protocol/content_description.h index 319d875..d655678 100644 --- a/remoting/protocol/content_description.h +++ b/remoting/protocol/content_description.h
@@ -47,7 +47,8 @@ buzz::XmlElement* ToXml() const; static scoped_ptr<ContentDescription> ParseXml( - const buzz::XmlElement* element); + const buzz::XmlElement* element, + bool webrtc_transport); private: scoped_ptr<const CandidateSessionConfig> candidate_config_;
diff --git a/remoting/protocol/content_description_unittest.cc b/remoting/protocol/content_description_unittest.cc index eebc39e..0d274b9 100644 --- a/remoting/protocol/content_description_unittest.cc +++ b/remoting/protocol/content_description_unittest.cc
@@ -24,7 +24,7 @@ scoped_ptr<buzz::XmlElement> xml(description.ToXml()); LOG(ERROR) << xml->Str(); scoped_ptr<ContentDescription> parsed( - ContentDescription::ParseXml(xml.get())); + ContentDescription::ParseXml(xml.get(), false)); ASSERT_TRUE(parsed.get()); EXPECT_TRUE(description.config()->control_configs() == parsed->config()->control_configs()); @@ -43,6 +43,7 @@ TEST(ContentDescriptionTest, ParseUnknown) { std::string kTestDescription = "<description xmlns=\"google:remoting\">" + " <standard-ice/>" " <control transport=\"stream\" version=\"2\"/>" " <event transport=\"stream\" version=\"2\"/>" " <event transport=\"new_awesome_transport\" version=\"3\"/>" @@ -51,7 +52,7 @@ "</description>"; scoped_ptr<buzz::XmlElement> xml(buzz::XmlElement::ForStr(kTestDescription)); scoped_ptr<ContentDescription> parsed( - ContentDescription::ParseXml(xml.get())); + ContentDescription::ParseXml(xml.get(), false)); ASSERT_TRUE(parsed.get()); EXPECT_EQ(1U, parsed->config()->event_configs().size()); EXPECT_TRUE(parsed->config()->event_configs().front() == @@ -65,6 +66,7 @@ TEST(ContentDescriptionTest, NoneTransport) { std::string kTestDescription = "<description xmlns=\"google:remoting\">" + " <standard-ice/>" " <control transport=\"stream\" version=\"2\"/>" " <event transport=\"stream\" version=\"2\"/>" " <event transport=\"stream\" version=\"2\"/>" @@ -74,7 +76,7 @@ "</description>"; scoped_ptr<buzz::XmlElement> xml(buzz::XmlElement::ForStr(kTestDescription)); scoped_ptr<ContentDescription> parsed( - ContentDescription::ParseXml(xml.get())); + ContentDescription::ParseXml(xml.get(), false)); ASSERT_TRUE(parsed.get()); EXPECT_EQ(1U, parsed->config()->audio_configs().size()); EXPECT_TRUE(parsed->config()->audio_configs().front() == ChannelConfig()); @@ -85,6 +87,7 @@ TEST(ContentDescriptionTest, NoneTransportWithCodec) { std::string kTestDescription = "<description xmlns=\"google:remoting\">" + " <standard-ice/>" " <control transport=\"stream\" version=\"2\"/>" " <event transport=\"stream\" version=\"2\"/>" " <event transport=\"stream\" version=\"2\"/>" @@ -94,7 +97,7 @@ "</description>"; scoped_ptr<buzz::XmlElement> xml(buzz::XmlElement::ForStr(kTestDescription)); scoped_ptr<ContentDescription> parsed( - ContentDescription::ParseXml(xml.get())); + ContentDescription::ParseXml(xml.get(), false)); ASSERT_TRUE(parsed.get()); EXPECT_EQ(1U, parsed->config()->audio_configs().size()); EXPECT_TRUE(parsed->config()->audio_configs().front() == ChannelConfig());
diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc index 2b73007..e0ec4b5 100644 --- a/remoting/protocol/jingle_messages.cc +++ b/remoting/protocol/jingle_messages.cc
@@ -249,6 +249,12 @@ return false; } + const XmlElement* webrtc_transport_tag = content_tag->FirstNamed( + QName("google:remoting:webrtc", "transport")); + if (webrtc_transport_tag) { + transport_info.reset(new buzz::XmlElement(*webrtc_transport_tag)); + } + description.reset(nullptr); if (action == SESSION_INITIATE || action == SESSION_ACCEPT) { const XmlElement* description_tag = content_tag->FirstNamed( @@ -258,17 +264,20 @@ return false; } - description = ContentDescription::ParseXml(description_tag); + description = ContentDescription::ParseXml(description_tag, + webrtc_transport_tag != nullptr); if (!description.get()) { *error = "Failed to parse content description"; return false; } } - const XmlElement* ice_transport_tag = content_tag->FirstNamed( - QName(kIceTransportNamespace, "transport")); - if (ice_transport_tag) { - transport_info.reset(new buzz::XmlElement(*ice_transport_tag)); + if (!webrtc_transport_tag) { + const XmlElement* ice_transport_tag = content_tag->FirstNamed( + QName(kIceTransportNamespace, "transport")); + if (ice_transport_tag) { + transport_info.reset(new buzz::XmlElement(*ice_transport_tag)); + } } return true;
diff --git a/remoting/protocol/jingle_messages_unittest.cc b/remoting/protocol/jingle_messages_unittest.cc index 7d075d49..7175277 100644 --- a/remoting/protocol/jingle_messages_unittest.cc +++ b/remoting/protocol/jingle_messages_unittest.cc
@@ -5,6 +5,7 @@ #include "remoting/protocol/jingle_messages.h" #include "base/logging.h" +#include "remoting/protocol/content_description.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" @@ -89,12 +90,41 @@ return true; } +// Parses |message_text| to JingleMessage. +void ParseJingleMessageFromXml(const char* message_text, + JingleMessage* parsed) { + scoped_ptr<XmlElement> source_message( + XmlElement::ForStr(message_text)); + ASSERT_TRUE(source_message.get()); + + EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); + + std::string error; + EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; +} + + +// Parses |message_text| to JingleMessage then attempts to format it to XML and +// verifies that the same XML content is generated. +void ParseFormatAndCompare(const char* message_text, JingleMessage* parsed) { + scoped_ptr<XmlElement> source_message( + XmlElement::ForStr(message_text)); + ASSERT_TRUE(source_message.get()); + + EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); + + std::string error; + EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; + + scoped_ptr<XmlElement> formatted_message(parsed->ToXml()); + ASSERT_TRUE(formatted_message.get()); + EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) + << error; +} + } // namespace -// Each of the tests below try to parse a message, format it again, -// and then verify that the formatted message is the same as the -// original stanza. The sample messages were generated by libjingle. - +// Session-initiate message for current ICE-based protocol. TEST(JingleMessageTest, SessionInitiate) { const char* kTestSessionInitiateMessage = "<iq to='user@gmail.com/chromoting016DBB07' type='set' " @@ -110,7 +140,6 @@ "<event transport='stream' version='2'/>" "<video transport='stream' version='2' codec='vp8'/>" "<audio transport='stream' version='2' codec='verbatim'/>" - "<initial-resolution width='640' height='480'/>" "<authentication><auth-token>" "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" "</auth-token></authentication>" @@ -118,31 +147,116 @@ "</content>" "</jingle>" "</iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestSessionInitiateMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + ParseFormatAndCompare(kTestSessionInitiateMessage, &message); EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(formatted_message.get(), source_message.get(), &error)) - << error; + EXPECT_FALSE(message.description->config()->webrtc_supported()); + EXPECT_TRUE(message.description->config()->ice_supported()); } +// Session-initiate message for WebRTC-based protocol. +TEST(JingleMessageTest, SessionInitiateWebrtc) { + const char* kTestSessionInitiateMessage = + "<iq to='user@gmail.com/chromoting016DBB07' type='set' " + "from='user@gmail.com/chromiumsy5C6A652D' " + "xmlns='jabber:client'>" + "<jingle xmlns='urn:xmpp:jingle:1' " + "action='session-initiate' sid='2227053353' " + "initiator='user@gmail.com/chromiumsy5C6A652D'>" + "<content name='chromoting' creator='initiator'>" + "<description xmlns='google:remoting'>" + "<authentication><auth-token>" + "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" + "</auth-token></authentication>" + "</description>" + "<transport xmlns='google:remoting:webrtc' />" + "</content>" + "</jingle>" + "</iq>"; + + JingleMessage message; + ParseFormatAndCompare(kTestSessionInitiateMessage, &message); + + EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE); + EXPECT_TRUE(message.description->config()->webrtc_supported()); + EXPECT_FALSE(message.description->config()->ice_supported()); +} + +// Session-initiate message for hybrid clients that support both versions of the +// protocol. +TEST(JingleMessageTest, SessionInitiateHybrid) { + const char* kTestSessionInitiateMessage = + "<iq to='user@gmail.com/chromoting016DBB07' type='set' " + "from='user@gmail.com/chromiumsy5C6A652D' " + "xmlns='jabber:client'>" + "<jingle xmlns='urn:xmpp:jingle:1' " + "action='session-initiate' sid='2227053353' " + "initiator='user@gmail.com/chromiumsy5C6A652D'>" + "<content name='chromoting' creator='initiator'>" + "<description xmlns='google:remoting'>" + "<standard-ice/>" + "<control transport='stream' version='2'/>" + "<event transport='stream' version='2'/>" + "<video transport='stream' version='2' codec='vp8'/>" + "<audio transport='stream' version='2' codec='verbatim'/>" + "<authentication><auth-token>" + "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" + "</auth-token></authentication>" + "</description>" + "<transport xmlns='google:remoting:webrtc' />" + "</content>" + "</jingle>" + "</iq>"; + + JingleMessage message; + ParseFormatAndCompare(kTestSessionInitiateMessage, &message); + + EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE); + EXPECT_TRUE(message.description->config()->webrtc_supported()); + EXPECT_TRUE(message.description->config()->ice_supported()); +} + +// Old GICE session-initiate message from older clients that are no longer +// supported. +TEST(JingleMessageTest, SessionInitiateNoIce) { + const char* kTestSessionInitiateMessage = + "<iq to='user@gmail.com/chromoting016DBB07' type='set' " + "from='user@gmail.com/chromiumsy5C6A652D' " + "xmlns='jabber:client'>" + "<jingle xmlns='urn:xmpp:jingle:1' " + "action='session-initiate' sid='2227053353' " + "initiator='user@gmail.com/chromiumsy5C6A652D'>" + "<content name='chromoting' creator='initiator'>" + "<description xmlns='google:remoting'>" + "<control transport='stream' version='2'/>" + "<event transport='stream' version='2'/>" + "<video transport='stream' version='2' codec='vp8'/>" + "<audio transport='stream' version='2' codec='verbatim'/>" + "<authentication><auth-token>" + "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" + "</auth-token></authentication>" + "</description>" + "</content>" + "</jingle>" + "</iq>"; + + JingleMessage message; + ParseJingleMessageFromXml(kTestSessionInitiateMessage, &message); + + EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE); + EXPECT_FALSE(message.description->config()->ice_supported()); +} + +// Session-accept message for current ICE-based protocol. TEST(JingleMessageTest, SessionAccept) { const char* kTestSessionAcceptMessage = "<cli:iq from='user@gmail.com/chromoting016DBB07' " "to='user@gmail.com/chromiumsy5C6A652D' type='set' " "xmlns:cli='jabber:client'>" "<jingle action='session-accept' sid='2227053353' " - "xmlns='urn:xmpp:jingle:1'>i" + "xmlns='urn:xmpp:jingle:1'>" "<content creator='initiator' name='chromoting'>" "<description xmlns='google:remoting'>" "<standard-ice/>" @@ -150,7 +264,6 @@ "<event transport='stream' version='2'/>" "<video codec='vp8' transport='stream' version='2'/>" "<audio transport='stream' version='2' codec='verbatim'/>" - "<initial-resolution height='480' width='640'/>" "<authentication><certificate>" "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA=" "</certificate></authentication>" @@ -159,38 +272,56 @@ "</jingle>" "</cli:iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestSessionAcceptMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); - JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + ParseFormatAndCompare(kTestSessionAcceptMessage, &message); EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) - << error; + EXPECT_FALSE(message.description->config()->webrtc_supported()); + EXPECT_TRUE(message.description->config()->ice_supported()); } +// Session-accept message for WebRTC-based protocol. +TEST(JingleMessageTest, SessionAcceptWebrtc) { + const char* kTestSessionAcceptMessage = + "<cli:iq from='user@gmail.com/chromoting016DBB07' " + "to='user@gmail.com/chromiumsy5C6A652D' type='set' " + "xmlns:cli='jabber:client'>" + "<jingle action='session-accept' sid='2227053353' " + "xmlns='urn:xmpp:jingle:1'>" + "<content creator='initiator' name='chromoting'>" + "<description xmlns='google:remoting'>" + "<authentication><certificate>" + "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA=" + "</certificate></authentication>" + "</description>" + "<transport xmlns='google:remoting:webrtc' />" + "</content>" + "</jingle>" + "</cli:iq>"; + + JingleMessage message; + ParseFormatAndCompare(kTestSessionAcceptMessage, &message); + + EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT); + EXPECT_TRUE(message.description->config()->webrtc_supported()); + EXPECT_FALSE(message.description->config()->ice_supported()); +} + +// Old GICE session-accept message from older host that are no longer +// supported. TEST(JingleMessageTest, SessionAcceptNoIce) { const char* kTestSessionAcceptMessage = "<cli:iq from='user@gmail.com/chromoting016DBB07' " "to='user@gmail.com/chromiumsy5C6A652D' type='set' " "xmlns:cli='jabber:client'>" "<jingle action='session-accept' sid='2227053353' " - "xmlns='urn:xmpp:jingle:1'>i" + "xmlns='urn:xmpp:jingle:1'>" "<content creator='initiator' name='chromoting'>" "<description xmlns='google:remoting'>" "<control transport='stream' version='2'/>" "<event transport='stream' version='2'/>" "<video codec='vp8' transport='stream' version='2'/>" "<audio transport='stream' version='2' codec='verbatim'/>" - "<initial-resolution height='480' width='640'/>" "<authentication><certificate>" "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA=" "</certificate></authentication>" @@ -199,22 +330,12 @@ "</jingle>" "</cli:iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestSessionAcceptMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); - JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + ParseJingleMessageFromXml(kTestSessionAcceptMessage, &message); EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) - << error; + EXPECT_FALSE(message.description->config()->ice_supported()); + EXPECT_FALSE(message.description->config()->webrtc_supported()); } TEST(JingleMessageTest, IceTransportInfo) { @@ -240,15 +361,8 @@ "</jingle>" "</cli:iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestIceTransportInfoMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); - JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + ParseFormatAndCompare(kTestIceTransportInfoMessage, &message); EXPECT_EQ(message.action, JingleMessage::TRANSPORT_INFO); @@ -256,11 +370,6 @@ EXPECT_TRUE(transport_info.ParseXml(message.transport_info.get())); EXPECT_EQ(transport_info.ice_credentials.size(), 2U); EXPECT_EQ(transport_info.candidates.size(), 2U); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) - << error; } TEST(JingleMessageTest, SessionTerminate) { @@ -271,51 +380,26 @@ "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>" "</reason></jingle></cli:iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestSessionTerminateMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); - JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; - + ParseFormatAndCompare(kTestSessionTerminateMessage, &message); EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) - << error; } TEST(JingleMessageTest, SessionInfo) { - const char* kTestSessionTerminateMessage = + const char* kTestSessionInfoMessage = "<cli:iq from='user@gmail.com/chromoting016DBB07' " "to='user@gmail.com/chromiumsy5C6A652D' type='set' " "xmlns:cli='jabber:client'><jingle action='session-info' " "sid='2227053353' xmlns='urn:xmpp:jingle:1'><test-info>TestMessage" "</test-info></jingle></cli:iq>"; - scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestSessionTerminateMessage)); - ASSERT_TRUE(source_message.get()); - - EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); - JingleMessage message; - std::string error; - EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + ParseFormatAndCompare(kTestSessionInfoMessage, &message); EXPECT_EQ(message.action, JingleMessage::SESSION_INFO); ASSERT_TRUE(message.info.get() != nullptr); EXPECT_TRUE(message.info->Name() == buzz::QName("urn:xmpp:jingle:1", "test-info")); - - scoped_ptr<XmlElement> formatted_message(message.ToXml()); - ASSERT_TRUE(formatted_message.get()); - EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) - << error; } TEST(JingleMessageReplyTest, ToXml) { @@ -397,7 +481,6 @@ "<event transport='stream' version='2'/>" "<video transport='stream' version='2' codec='vp8'/>" "<audio transport='stream' version='2' codec='verbatim'/>" - "<initial-resolution width='800' height='600'/>" "<authentication><auth-token>" "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" "</auth-token></authentication>"
diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc index 8e0b557..21dac5c3 100644 --- a/remoting/protocol/jingle_session_unittest.cc +++ b/remoting/protocol/jingle_session_unittest.cc
@@ -429,7 +429,7 @@ scoped_ptr<CandidateSessionConfig> config = CandidateSessionConfig::CreateDefault(); - config->set_standard_ice(false); + config->set_ice_supported(false); client_server_->set_protocol_config(config.Pass()); client_session_ = client_server_->Connect(kHostJid, authenticator.Pass()); client_session_->SetEventHandler(&client_session_event_handler_);
diff --git a/remoting/protocol/session_config.cc b/remoting/protocol/session_config.cc index 9034cea..0aa2c8ed 100644 --- a/remoting/protocol/session_config.cc +++ b/remoting/protocol/session_config.cc
@@ -73,18 +73,21 @@ scoped_ptr<SessionConfig> SessionConfig::SelectCommon( const CandidateSessionConfig* client_config, const CandidateSessionConfig* host_config) { - scoped_ptr<SessionConfig> result(new SessionConfig()); + + // Use WebRTC if both host and client support it. + if (client_config->webrtc_supported() && host_config->webrtc_supported()) + return make_scoped_ptr(new SessionConfig(Protocol::WEBRTC)); + + // Reject connection if ICE is not supported by either of the peers. + if (!host_config->ice_supported() || !client_config->ice_supported()) + return nullptr; + + scoped_ptr<SessionConfig> result(new SessionConfig(Protocol::ICE)); ChannelConfig control_config; ChannelConfig event_config; ChannelConfig video_config; ChannelConfig audio_config; - DCHECK(host_config->standard_ice()); - - // Reject connection if the peer doesn't support ICE. - if (!client_config->standard_ice()) - return nullptr; - // If neither host nor the client have VP9 experiment enabled then remove it // from the list of host video configs. std::list<ChannelConfig> host_video_configs = host_config->video_configs(); @@ -116,6 +119,17 @@ // static scoped_ptr<SessionConfig> SessionConfig::GetFinalConfig( const CandidateSessionConfig* candidate_config) { + if (candidate_config->webrtc_supported()) { + if (candidate_config->ice_supported()) { + LOG(ERROR) << "Received candidate config is ambiguous."; + return nullptr; + } + return make_scoped_ptr(new SessionConfig(Protocol::WEBRTC)); + } + + if (!candidate_config->ice_supported()) + return nullptr; + if (candidate_config->control_configs().size() != 1 || candidate_config->event_configs().size() != 1 || candidate_config->video_configs().size() != 1 || @@ -123,19 +137,18 @@ return nullptr; } - scoped_ptr<SessionConfig> result(new SessionConfig()); - result->standard_ice_ = candidate_config->standard_ice(); + scoped_ptr<SessionConfig> result(new SessionConfig(Protocol::ICE)); result->control_config_ = candidate_config->control_configs().front(); result->event_config_ = candidate_config->event_configs().front(); result->video_config_ = candidate_config->video_configs().front(); result->audio_config_ = candidate_config->audio_configs().front(); - return result.Pass(); + return result; } // static scoped_ptr<SessionConfig> SessionConfig::ForTest() { - scoped_ptr<SessionConfig> result(new SessionConfig()); + scoped_ptr<SessionConfig> result(new SessionConfig(Protocol::ICE)); result->control_config_ = ChannelConfig(ChannelConfig::TRANSPORT_QUIC_STREAM, kControlStreamVersion, ChannelConfig::CODEC_UNDEFINED); @@ -159,7 +172,36 @@ return result.Pass(); } -SessionConfig::SessionConfig() {} +scoped_ptr<SessionConfig> SessionConfig::ForTestWithWebrtc() { + return make_scoped_ptr(new SessionConfig(Protocol::WEBRTC)); +} + +const ChannelConfig& SessionConfig::control_config() const { + DCHECK(protocol_ == Protocol::ICE); + return control_config_; +} +const ChannelConfig& SessionConfig::event_config() const { + DCHECK(protocol_ == Protocol::ICE); + return event_config_; +} +const ChannelConfig& SessionConfig::video_config() const { + DCHECK(protocol_ == Protocol::ICE); + return video_config_; +} +const ChannelConfig& SessionConfig::audio_config() const { + DCHECK(protocol_ == Protocol::ICE); + return audio_config_; +} + +bool SessionConfig::is_using_quic() const { + DCHECK(protocol_ == Protocol::ICE); + return control_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || + event_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || + video_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || + audio_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM; +} + +SessionConfig::SessionConfig(Protocol protocol) : protocol_(protocol) {} CandidateSessionConfig::CandidateSessionConfig() {} CandidateSessionConfig::CandidateSessionConfig( @@ -167,11 +209,21 @@ CandidateSessionConfig::~CandidateSessionConfig() {} bool CandidateSessionConfig::IsSupported(const SessionConfig& config) const { - return config.standard_ice() && - IsChannelConfigSupported(control_configs_, config.control_config()) && - IsChannelConfigSupported(event_configs_, config.event_config()) && - IsChannelConfigSupported(video_configs_, config.video_config()) && - IsChannelConfigSupported(audio_configs_, config.audio_config()); + switch (config.protocol()) { + case SessionConfig::Protocol::ICE: + return ice_supported() && + IsChannelConfigSupported(control_configs_, + config.control_config()) && + IsChannelConfigSupported(event_configs_, config.event_config()) && + IsChannelConfigSupported(video_configs_, config.video_config()) && + IsChannelConfigSupported(audio_configs_, config.audio_config()); + + case SessionConfig::Protocol::WEBRTC: + return webrtc_supported(); + } + + NOTREACHED(); + return false; } scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::Clone() const { @@ -187,11 +239,23 @@ scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateFrom( const SessionConfig& config) { scoped_ptr<CandidateSessionConfig> result = CreateEmpty(); - result->set_standard_ice(config.standard_ice()); - result->mutable_control_configs()->push_back(config.control_config()); - result->mutable_event_configs()->push_back(config.event_config()); - result->mutable_video_configs()->push_back(config.video_config()); - result->mutable_audio_configs()->push_back(config.audio_config()); + + switch (config.protocol()) { + case SessionConfig::Protocol::WEBRTC: + result->set_webrtc_supported(true); + result->set_ice_supported(false); + break; + + case SessionConfig::Protocol::ICE: + result->set_webrtc_supported(false); + result->set_ice_supported(true); + result->mutable_control_configs()->push_back(config.control_config()); + result->mutable_event_configs()->push_back(config.event_config()); + result->mutable_video_configs()->push_back(config.video_config()); + result->mutable_audio_configs()->push_back(config.audio_config()); + break; + } + return result.Pass(); } @@ -199,6 +263,8 @@ scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateDefault() { scoped_ptr<CandidateSessionConfig> result = CreateEmpty(); + result->set_ice_supported(true); + // Control channel. result->mutable_control_configs()->push_back( ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
diff --git a/remoting/protocol/session_config.h b/remoting/protocol/session_config.h index cc444a08..591a6af 100644 --- a/remoting/protocol/session_config.h +++ b/remoting/protocol/session_config.h
@@ -59,10 +59,20 @@ class CandidateSessionConfig; -// SessionConfig is used by the chromoting Session to store negotiated -// chromotocol configuration. +// SessionConfig is used to represent negotiated session configuration. Note +// that it's useful mainly for the legacy protocol. When using the new +// WebRTC-based protocol the using_webrtc() flag is set to true and all other +// fields should be ignored. class SessionConfig { public: + enum class Protocol { + // Current ICE-based protocol. + ICE, + + // New WebRTC-based protocol. + WEBRTC, + }; + // Selects session configuration that is supported by both participants. // nullptr is returned if such configuration doesn't exist. When selecting // channel configuration priority is given to the configs listed first @@ -82,30 +92,27 @@ // Returns a suitable session configuration for use in tests. static scoped_ptr<SessionConfig> ForTest(); static scoped_ptr<SessionConfig> ForTestWithVerbatimVideo(); + static scoped_ptr<SessionConfig> ForTestWithWebrtc(); - bool standard_ice() const { return standard_ice_; } + Protocol protocol() const { return protocol_; } - const ChannelConfig& control_config() const { return control_config_; } - const ChannelConfig& event_config() const { return event_config_; } - const ChannelConfig& video_config() const { return video_config_; } - const ChannelConfig& audio_config() const { return audio_config_; } + // All fields below should be ignored when protocol() is set to WEBRTC. + const ChannelConfig& control_config() const; + const ChannelConfig& event_config() const; + const ChannelConfig& video_config() const; + const ChannelConfig& audio_config() const; bool is_audio_enabled() const { return audio_config_.transport != ChannelConfig::TRANSPORT_NONE; } // Returns true if any of the channels is using QUIC. - bool is_using_quic() const { - return control_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || - event_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || - video_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM || - audio_config_.transport == ChannelConfig::TRANSPORT_QUIC_STREAM; - } + bool is_using_quic() const; private: - SessionConfig(); + SessionConfig(Protocol protocol); - bool standard_ice_ = true; + const Protocol protocol_; ChannelConfig control_config_; ChannelConfig event_config_; @@ -125,8 +132,13 @@ ~CandidateSessionConfig(); - bool standard_ice() const { return standard_ice_; } - void set_standard_ice(bool standard_ice) { standard_ice_ = standard_ice; } + bool webrtc_supported() const { return webrtc_supported_; } + void set_webrtc_supported(bool webrtc_supported) { + webrtc_supported_ = webrtc_supported; + } + + bool ice_supported() const { return ice_supported_; } + void set_ice_supported(bool ice_supported) { ice_supported_ = ice_supported; } const std::list<ChannelConfig>& control_configs() const { return control_configs_; @@ -186,7 +198,8 @@ explicit CandidateSessionConfig(const CandidateSessionConfig& config); CandidateSessionConfig& operator=(const CandidateSessionConfig& b); - bool standard_ice_ = true; + bool webrtc_supported_ = false; + bool ice_supported_ = false; std::list<ChannelConfig> control_configs_; std::list<ChannelConfig> event_configs_;
diff --git a/remoting/protocol/session_config_unittest.cc b/remoting/protocol/session_config_unittest.cc new file mode 100644 index 0000000..466815f8 --- /dev/null +++ b/remoting/protocol/session_config_unittest.cc
@@ -0,0 +1,110 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/session_config.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { +namespace protocol { + +void TestGetFinalConfig(scoped_ptr<SessionConfig> config) { + scoped_ptr<CandidateSessionConfig> candidate_config = + CandidateSessionConfig::CreateFrom(*config); + ASSERT_TRUE(candidate_config); + scoped_ptr<SessionConfig> config2 = + SessionConfig::GetFinalConfig(candidate_config.get()); + ASSERT_TRUE(config2); + EXPECT_EQ(config->protocol(), config2->protocol()); + + if (config->protocol() == SessionConfig::Protocol::ICE) { + EXPECT_EQ(config->control_config(), config2->control_config()); + EXPECT_EQ(config->event_config(), config2->event_config()); + EXPECT_EQ(config->video_config(), config2->video_config()); + EXPECT_EQ(config->audio_config(), config2->audio_config()); + } +} + +TEST(SessionConfig, SelectCommon) { + scoped_ptr<CandidateSessionConfig> default_candidate_config = + CandidateSessionConfig::CreateDefault(); + + scoped_ptr<CandidateSessionConfig> candidate_config_with_webrtc = + CandidateSessionConfig::CreateEmpty(); + candidate_config_with_webrtc->set_webrtc_supported(true); + + scoped_ptr<CandidateSessionConfig> hybrid_candidate_config = + CandidateSessionConfig::CreateDefault(); + hybrid_candidate_config->set_webrtc_supported(true); + + scoped_ptr<SessionConfig> selected; + + // ICE is selected by default. + selected = SessionConfig::SelectCommon(default_candidate_config.get(), + default_candidate_config.get()); + ASSERT_TRUE(selected); + EXPECT_EQ(SessionConfig::Protocol::ICE, selected->protocol()); + + // WebRTC protocol is not supported by default. + selected = SessionConfig::SelectCommon(default_candidate_config.get(), + candidate_config_with_webrtc.get()); + EXPECT_FALSE(selected); + + // ICE is selected when client supports both protocols + selected = SessionConfig::SelectCommon(default_candidate_config.get(), + hybrid_candidate_config.get()); + ASSERT_TRUE(selected); + EXPECT_EQ(SessionConfig::Protocol::ICE, selected->protocol()); + + // WebRTC is selected when both peers support it. + selected = SessionConfig::SelectCommon(candidate_config_with_webrtc.get(), + candidate_config_with_webrtc.get()); + ASSERT_TRUE(selected); + EXPECT_EQ(SessionConfig::Protocol::WEBRTC, selected->protocol()); + + // WebRTC is selected when both peers support it. + selected = SessionConfig::SelectCommon(candidate_config_with_webrtc.get(), + hybrid_candidate_config.get()); + ASSERT_TRUE(selected); + EXPECT_EQ(SessionConfig::Protocol::WEBRTC, selected->protocol()); + + // ICE is selected if both peers support both protocols. + selected = SessionConfig::SelectCommon(hybrid_candidate_config.get(), + hybrid_candidate_config.get()); + ASSERT_TRUE(selected); + EXPECT_EQ(SessionConfig::Protocol::WEBRTC, selected->protocol()); +} + +TEST(SessionConfig, GetFinalConfig) { + TestGetFinalConfig(SessionConfig::ForTest()); + TestGetFinalConfig(SessionConfig::ForTestWithWebrtc()); +} + +TEST(SessionConfig, IsSupported) { + scoped_ptr<CandidateSessionConfig> default_candidate_config = + CandidateSessionConfig::CreateDefault(); + + scoped_ptr<CandidateSessionConfig> candidate_config_with_webrtc = + CandidateSessionConfig::CreateEmpty(); + candidate_config_with_webrtc->set_webrtc_supported(true); + + scoped_ptr<CandidateSessionConfig> hybrid_candidate_config = + CandidateSessionConfig::CreateDefault(); + hybrid_candidate_config->set_webrtc_supported(true); + + scoped_ptr<SessionConfig> ice_config = SessionConfig::ForTest(); + scoped_ptr<SessionConfig> webrtc_config = SessionConfig::ForTestWithWebrtc(); + + EXPECT_TRUE(default_candidate_config->IsSupported(*ice_config)); + EXPECT_FALSE(default_candidate_config->IsSupported(*webrtc_config)); + + EXPECT_FALSE(candidate_config_with_webrtc->IsSupported(*ice_config)); + EXPECT_TRUE(candidate_config_with_webrtc->IsSupported(*webrtc_config)); + + EXPECT_TRUE(hybrid_candidate_config->IsSupported(*ice_config)); + EXPECT_TRUE(hybrid_candidate_config->IsSupported(*webrtc_config)); +} + +} // namespace protocol +} // namespace remoting
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index e3d0ced..256bd0d 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi
@@ -328,6 +328,7 @@ 'protocol/ppapi_module_stub.cc', 'protocol/pseudotcp_adapter_unittest.cc', 'protocol/quic_channel_factory_unittest.cc', + 'protocol/session_config_unittest.cc', 'protocol/ssl_hmac_channel_authenticator_unittest.cc', 'protocol/third_party_authenticator_unittest.cc', 'protocol/v2_authenticator_unittest.cc',
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc index 580cad2..2f66b40b 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -8,6 +8,7 @@ #include <unistd.h> #include <iostream> +#include <utility> #include "base/files/scoped_file.h" #include "base/posix/eintr_wrapper.h" @@ -71,7 +72,7 @@ { SandboxBPF sandbox(nullptr); - sandbox.SetProcFd(write_end.Pass()); + sandbox.SetProcFd(std::move(write_end)); } ASSERT_EQ(0, fcntl(read_end.get(), F_SETFL, O_NONBLOCK));
diff --git a/sandbox/linux/services/proc_util.cc b/sandbox/linux/services/proc_util.cc index 8341b4a..247c29c 100644 --- a/sandbox/linux/services/proc_util.cc +++ b/sandbox/linux/services/proc_util.cc
@@ -33,7 +33,7 @@ base::ScopedFD directory_fd( HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC))); PCHECK(directory_fd.is_valid()); - return directory_fd.Pass(); + return directory_fd; } } // namespace
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc index 760cf59b..db8201ae 100644 --- a/sandbox/linux/syscall_broker/broker_client.cc +++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -9,6 +9,7 @@ #include <sys/stat.h> #include <sys/socket.h> #include <sys/types.h> +#include <utility> #include "build/build_config.h" #include "base/logging.h" @@ -123,10 +124,9 @@ bool fast_check_in_client, bool quiet_failures_for_tests) : broker_policy_(broker_policy), - ipc_channel_(ipc_channel.Pass()), + ipc_channel_(std::move(ipc_channel)), fast_check_in_client_(fast_check_in_client), - quiet_failures_for_tests_(quiet_failures_for_tests) { -} + quiet_failures_for_tests_(quiet_failures_for_tests) {} BrokerClient::~BrokerClient() { }
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc index 8b78b1b..1a0568f 100644 --- a/sandbox/linux/syscall_broker/broker_host.cc +++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -13,6 +13,7 @@ #include <unistd.h> #include <string> +#include <utility> #include <vector> #include "base/files/scoped_file.h" @@ -163,8 +164,7 @@ BrokerHost::BrokerHost(const BrokerPolicy& broker_policy, BrokerChannel::EndPoint ipc_channel) - : broker_policy_(broker_policy), ipc_channel_(ipc_channel.Pass()) { -} + : broker_policy_(broker_policy), ipc_channel_(std::move(ipc_channel)) {} BrokerHost::~BrokerHost() { } @@ -193,7 +193,7 @@ return RequestStatus::FAILURE; } - base::ScopedFD temporary_ipc(fds[0]->Pass()); + base::ScopedFD temporary_ipc(std::move(*fds[0])); base::Pickle pickle(buf, msg_len); base::PickleIterator iter(pickle);
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc index 81131cc..5ab8c6c 100644 --- a/sandbox/linux/syscall_broker/broker_process.cc +++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -14,6 +14,7 @@ #include <algorithm> #include <string> +#include <utility> #include <vector> #include "base/callback.h" @@ -75,7 +76,7 @@ // We are the parent and we have just forked our broker process. ipc_reader.reset(); broker_pid_ = child_pid; - broker_client_.reset(new BrokerClient(policy_, ipc_writer.Pass(), + broker_client_.reset(new BrokerClient(policy_, std::move(ipc_writer), fast_check_in_client_, quiet_failures_for_tests_)); initialized_ = true; @@ -85,7 +86,7 @@ // we get notified if the client disappears. ipc_writer.reset(); CHECK(broker_process_init_callback.Run()); - BrokerHost broker_host(policy_, ipc_reader.Pass()); + BrokerHost broker_host(policy_, std::move(ipc_reader)); for (;;) { switch (broker_host.HandleRequest()) { case BrokerHost::RequestStatus::LOST_CLIENT:
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 7b84e1d..61786ad 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -214,6 +214,10 @@ # define SK_SUPPORT_LEGACY_GETDEVICE #endif +#ifndef SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS +# define SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS +#endif + #ifndef SK_IGNORE_ETC1_SUPPORT # define SK_IGNORE_ETC1_SUPPORT #endif
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index e3bfa81..1b96575 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn
@@ -6,6 +6,10 @@ component("browser") { output_name = "storage_browser" sources = [ + "blob/blob_async_builder_host.cc", + "blob/blob_async_builder_host.h", + "blob/blob_async_transport_strategy.cc", + "blob/blob_async_transport_strategy.h", "blob/blob_data_builder.cc", "blob/blob_data_builder.h", "blob/blob_data_handle.cc",
diff --git a/storage/browser/blob/blob_async_builder_host.cc b/storage/browser/blob/blob_async_builder_host.cc new file mode 100644 index 0000000..1cd2e777 --- /dev/null +++ b/storage/browser/blob/blob_async_builder_host.cc
@@ -0,0 +1,273 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/blob/blob_async_builder_host.h" + +#include <utility> + +#include "base/memory/shared_memory.h" + +namespace storage { + +using MemoryItemRequest = BlobAsyncTransportStrategy::RendererMemoryItemRequest; + +BlobAsyncBuilderHost::BlobBuildingState::BlobBuildingState() + : next_request(0), + num_fulfilled_requests(0), + num_shared_memory_requests(0), + current_shared_memory_handle_index(0) {} + +BlobAsyncBuilderHost::BlobBuildingState::~BlobBuildingState() {} + +BlobAsyncBuilderHost::BlobAsyncBuilderHost() {} + +BlobAsyncBuilderHost::~BlobAsyncBuilderHost() {} + +bool BlobAsyncBuilderHost::StartBuildingBlob( + const std::string& uuid, + const std::string& type, + const std::vector<DataElement>& descriptions, + size_t memory_available, + const base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)>& request_memory, + const base::Callback<void(const BlobDataBuilder&)>& done, + const base::Callback<void(IPCBlobCreationCancelCode)>& cancel) { + if (async_blob_map_.find(uuid) != async_blob_map_.end()) + return false; + if (BlobAsyncTransportStrategy::ShouldBeShortcut(descriptions, + memory_available)) { + // We have enough memory, and all the data is here, so we use the shortcut + // method and populate the old way. + BlobDataBuilder builder(uuid); + builder.set_content_type(type); + for (const DataElement& element : descriptions) { + builder.AppendIPCDataElement(element); + } + done.Run(builder); + return true; + } + + scoped_ptr<BlobBuildingState> state(new BlobBuildingState()); + BlobBuildingState* state_ptr = state.get(); + async_blob_map_[uuid] = std::move(state); + state_ptr->type = type; + state_ptr->request_memory_callback = request_memory; + state_ptr->done_callback = done; + state_ptr->cancel_callback = cancel; + + // We are currently only operating in 'no disk' mode. This will change in + // future patches to enable disk storage. + // Since we don't have a disk yet, we put 0 for disk_space_left. + state_ptr->transport_strategy.Initialize( + max_ipc_memory_size_, max_shared_memory_size_, max_file_size_, + 0 /* disk_space_left */, memory_available, uuid, descriptions); + + switch (state_ptr->transport_strategy.error()) { + case BlobAsyncTransportStrategy::ERROR_TOO_LARGE: + // Cancel cleanly, we're out of memory. + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return true; + case BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS: + // Bad IPC, so we ignore and clean up. + VLOG(1) << "Error initializing transport strategy: " + << state_ptr->transport_strategy.error(); + async_blob_map_.erase(async_blob_map_.find(uuid)); + return false; + case BlobAsyncTransportStrategy::ERROR_NONE: + ContinueBlobMemoryRequests(uuid); + return true; + } + return false; +} + +bool BlobAsyncBuilderHost::OnMemoryResponses( + const std::string& uuid, + const std::vector<BlobItemBytesResponse>& responses) { + if (responses.empty()) { + return false; + } + AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid); + if (state_it == async_blob_map_.end()) { + // There's a possibility that we had a shared memory error, and there were + // still responses in flight. So we don't fail here, we just ignore. + DVLOG(1) << "Could not find blob " << uuid; + return true; + } + BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get(); + BlobAsyncTransportStrategy& strategy = state->transport_strategy; + bool invalid_ipc = false; + bool memory_error = false; + const auto& requests = strategy.requests(); + for (const BlobItemBytesResponse& response : responses) { + if (response.request_number >= requests.size()) { + // Bad IPC, so we delete our record and ignore. + DVLOG(1) << "Invalid request number " << response.request_number; + async_blob_map_.erase(state_it); + return false; + } + const MemoryItemRequest& request = requests[response.request_number]; + if (request.received) { + // Bad IPC, so we delete our record. + DVLOG(1) << "Already received response for that request."; + async_blob_map_.erase(state_it); + return false; + } + strategy.MarkRequestAsReceived(response.request_number); + switch (request.message.transport_strategy) { + case IPCBlobItemRequestStrategy::IPC: + if (response.inline_data.size() < request.message.size) { + DVLOG(1) << "Invalid data size " << response.inline_data.size() + << " vs requested size of " << request.message.size; + invalid_ipc = true; + break; + } + invalid_ipc = !strategy.blob_builder()->PopulateFutureData( + request.browser_item_index, &response.inline_data[0], + request.browser_item_offset, request.message.size); + break; + case IPCBlobItemRequestStrategy::SHARED_MEMORY: + if (state->num_shared_memory_requests == 0) { + DVLOG(1) << "Received too many responses for shared memory."; + invalid_ipc = true; + break; + } + state->num_shared_memory_requests--; + if (!state->shared_memory_block->memory()) { + // We just map the whole block, as we'll probably be accessing the + // whole thing in this group of responses. Another option is to use + // MapAt, remove the mapped boolean, and then exclude the + // handle_offset below. + size_t handle_size = strategy.handle_sizes().at( + state->current_shared_memory_handle_index); + if (!state->shared_memory_block->Map(handle_size)) { + DVLOG(1) << "Unable to map memory to size " << handle_size; + memory_error = true; + break; + } + } + + invalid_ipc = !strategy.blob_builder()->PopulateFutureData( + request.browser_item_index, + static_cast<const char*>(state->shared_memory_block->memory()) + + request.message.handle_offset, + request.browser_item_offset, request.message.size); + break; + case IPCBlobItemRequestStrategy::FILE: + case IPCBlobItemRequestStrategy::UNKNOWN: + DVLOG(1) << "Not implemented."; + invalid_ipc = true; + break; + } + if (invalid_ipc) { + // Bad IPC, so we delete our record and return false. + async_blob_map_.erase(state_it); + return false; + } + if (memory_error) { + DVLOG(1) << "Shared memory error."; + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return true; + } + state->num_fulfilled_requests++; + } + ContinueBlobMemoryRequests(uuid); + return true; +} + +void BlobAsyncBuilderHost::StopBuildingBlob(const std::string& uuid) { + async_blob_map_.erase(async_blob_map_.find(uuid)); +} + +void BlobAsyncBuilderHost::ContinueBlobMemoryRequests(const std::string& uuid) { + AsyncBlobMap::const_iterator state_it = async_blob_map_.find(uuid); + DCHECK(state_it != async_blob_map_.end()); + BlobAsyncBuilderHost::BlobBuildingState* state = state_it->second.get(); + + const std::vector<MemoryItemRequest>& requests = + state->transport_strategy.requests(); + BlobAsyncTransportStrategy& strategy = state->transport_strategy; + size_t num_requests = requests.size(); + if (state->num_fulfilled_requests == num_requests) { + DoneAndCleanup(uuid); + return; + } + DCHECK_LT(state->num_fulfilled_requests, num_requests); + if (state->next_request == num_requests) { + // We are still waiting on other requests to come back. + return; + } + + std::vector<BlobItemBytesRequest> byte_requests; + std::vector<base::SharedMemoryHandle> shared_memory; + std::vector<uint64_t> files; + + for (; state->next_request < num_requests; ++state->next_request) { + const MemoryItemRequest& request = requests[state->next_request]; + + bool stop_accumulating = false; + bool using_shared_memory_handle = state->num_shared_memory_requests > 0; + switch (request.message.transport_strategy) { + case IPCBlobItemRequestStrategy::IPC: + byte_requests.push_back(request.message); + break; + case IPCBlobItemRequestStrategy::SHARED_MEMORY: + if (using_shared_memory_handle && + state->current_shared_memory_handle_index != + request.message.handle_index) { + // We only want one shared memory per requesting blob. + stop_accumulating = true; + break; + } + using_shared_memory_handle = true; + state->current_shared_memory_handle_index = + request.message.handle_index; + state->num_shared_memory_requests++; + + if (!state->shared_memory_block) { + state->shared_memory_block.reset(new base::SharedMemory()); + size_t size = strategy.handle_sizes()[request.message.handle_index]; + if (!state->shared_memory_block->CreateAnonymous(size)) { + DVLOG(1) << "Unable to allocate shared memory for blob transfer."; + CancelAndCleanup(uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY); + return; + } + } + shared_memory.push_back(state->shared_memory_block->handle()); + byte_requests.push_back(request.message); + // Since we are only using one handle at a time, transform our handle + // index correctly back to 0. + byte_requests.back().handle_index = 0; + break; + case IPCBlobItemRequestStrategy::FILE: + case IPCBlobItemRequestStrategy::UNKNOWN: + NOTREACHED() << "Not implemented yet."; + break; + } + if (stop_accumulating) { + break; + } + } + + DCHECK(!requests.empty()); + + state->request_memory_callback.Run(byte_requests, shared_memory, files); +} + +void BlobAsyncBuilderHost::CancelAndCleanup(const std::string& uuid, + IPCBlobCreationCancelCode code) { + scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]); + async_blob_map_.erase(uuid); + state->cancel_callback.Run(code); +} + +void BlobAsyncBuilderHost::DoneAndCleanup(const std::string& uuid) { + scoped_ptr<BlobBuildingState> state = std::move(async_blob_map_[uuid]); + async_blob_map_.erase(uuid); + BlobDataBuilder* builder = state->transport_strategy.blob_builder(); + builder->set_content_type(state->type); + state->done_callback.Run(*builder); +} + +} // namespace storage
diff --git a/storage/browser/blob/blob_async_builder_host.h b/storage/browser/blob/blob_async_builder_host.h new file mode 100644 index 0000000..0e4a0d4 --- /dev/null +++ b/storage/browser/blob/blob_async_builder_host.h
@@ -0,0 +1,129 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_ +#define STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory_handle.h" +#include "storage/browser/blob/blob_async_transport_strategy.h" +#include "storage/browser/blob/blob_data_builder.h" +#include "storage/browser/storage_browser_export.h" +#include "storage/common/blob_storage/blob_item_bytes_request.h" +#include "storage/common/blob_storage/blob_item_bytes_response.h" +#include "storage/common/blob_storage/blob_storage_constants.h" +#include "storage/common/data_element.h" + +namespace base { +class SharedMemory; +} + +namespace storage { + +// This class holds all blobs that are currently being built asynchronously for +// a child process. It sends memory request, cancel, and done messages through +// the given callbacks. +// This also includes handling 'shortcut' logic, where the host will use the +// initial data in the description instead of requesting for data if we have +// enough immediate space. +class STORAGE_EXPORT BlobAsyncBuilderHost { + public: + BlobAsyncBuilderHost(); + virtual ~BlobAsyncBuilderHost(); + + // This method begins the construction of the blob given the descriptions. + // After this method is called, either of the following can happen. + // * The |done| callback is triggered immediately because we can shortcut the + // construction. + // * The |request_memory| callback is called to request memory from the + // renderer. This class waits for calls to OnMemoryResponses to continue. + // The last argument in the callback corresponds to file handle sizes. + // When all memory is recieved, the |done| callback is triggered. + // * The |cancel| callback is triggered if there is an error at any point. All + // state for the cancelled blob is cleared before |cancel| is called. + // Returns if the arguments are valid and we have a good IPC message. + bool StartBuildingBlob( + const std::string& uuid, + const std::string& type, + const std::vector<DataElement>& descriptions, + size_t memory_available, + const base::Callback< + void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)>& request_memory, + const base::Callback<void(const BlobDataBuilder&)>& done, + const base::Callback<void(IPCBlobCreationCancelCode)>& cancel); + + // This is called when we have responses from the Renderer to our calls to + // the request_memory callback above. + // Returns if the arguments are valid and we have a good IPC message. + bool OnMemoryResponses(const std::string& uuid, + const std::vector<BlobItemBytesResponse>& responses); + + // This erases the blob building state. + void StopBuildingBlob(const std::string& uuid); + + size_t blob_building_count() const { return async_blob_map_.size(); } + + // For testing use only. Must be called before StartBuildingBlob. + void SetMemoryConstantsForTesting(size_t max_ipc_memory_size, + size_t max_shared_memory_size, + uint64_t max_file_size) { + max_ipc_memory_size_ = max_ipc_memory_size; + max_shared_memory_size_ = max_shared_memory_size; + max_file_size_ = max_file_size; + } + + private: + struct BlobBuildingState { + BlobBuildingState(); + ~BlobBuildingState(); + + std::string type; + BlobAsyncTransportStrategy transport_strategy; + size_t next_request; + size_t num_fulfilled_requests; + scoped_ptr<base::SharedMemory> shared_memory_block; + // This is the number of requests that have been sent to populate the above + // shared data. We won't ask for more data in shared memory until all + // requests have been responded to. + size_t num_shared_memory_requests; + // Only relevant if num_shared_memory_requests is > 0 + size_t current_shared_memory_handle_index; + + base::Callback<void(const std::vector<storage::BlobItemBytesRequest>&, + const std::vector<base::SharedMemoryHandle>&, + const std::vector<uint64_t>&)> request_memory_callback; + base::Callback<void(const BlobDataBuilder&)> done_callback; + base::Callback<void(IPCBlobCreationCancelCode)> cancel_callback; + }; + + typedef std::map<std::string, scoped_ptr<BlobBuildingState>> AsyncBlobMap; + + // This is the 'main loop' of our memory requests to the renderer. + void ContinueBlobMemoryRequests(const std::string& uuid); + + void CancelAndCleanup(const std::string& uuid, + IPCBlobCreationCancelCode code); + void DoneAndCleanup(const std::string& uuid); + + AsyncBlobMap async_blob_map_; + + // Here for testing. + size_t max_ipc_memory_size_ = kBlobStorageIPCThresholdBytes; + size_t max_shared_memory_size_ = kBlobStorageMaxSharedMemoryBytes; + uint64_t max_file_size_ = kBlobStorageMaxFileSizeBytes; + + DISALLOW_COPY_AND_ASSIGN(BlobAsyncBuilderHost); +}; + +} // namespace storage +#endif // STORAGE_BROWSER_BLOB_BLOB_ASYNC_BUILDER_HOST_H_
diff --git a/storage/browser/blob/blob_async_transport_strategy.cc b/storage/browser/blob/blob_async_transport_strategy.cc new file mode 100644 index 0000000..8dbe52e --- /dev/null +++ b/storage/browser/blob/blob_async_transport_strategy.cc
@@ -0,0 +1,334 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <algorithm> + +#include "base/numerics/safe_math.h" +#include "storage/browser/blob/blob_async_transport_strategy.h" +#include "storage/common/blob_storage/blob_storage_constants.h" + +namespace storage { +namespace { +bool IsBytes(DataElement::Type type) { + return type == DataElement::TYPE_BYTES || + type == DataElement::TYPE_BYTES_DESCRIPTION; +} + +// This is the general template that each strategy below implements. See the +// ForEachWithSegment method for a description of how these are called. +// class BlobSegmentVisitor { +// public: +// typedef ___ SizeType; +// void VisitBytesSegment(size_t element_index, uint64_t element_offset, +// size_t segment_index, uint64_t segment_offset, +// uint64_t size); +// void VisitNonBytesSegment(const DataElement& element, size_t element_idx); +// void Done(); +// }; + +// This class handles the logic of how transported memory is going to be +// represented as storage in the browser. The main idea is that all the memory +// is now packed into file chunks, and the browser items will just reference +// the file with offsets and sizes. +class FileStorageStrategy { + public: + FileStorageStrategy( + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* + requests, + BlobDataBuilder* builder) + : requests(requests), builder(builder), current_item_index(0) {} + + ~FileStorageStrategy() {} + + void VisitBytesSegment(size_t element_index, + uint64_t element_offset, + size_t segment_index, + uint64_t segment_offset, + uint64_t size) { + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = current_item_index; + request.browser_item_offset = 0; + request.message.request_number = requests->size(); + request.message.transport_strategy = IPCBlobItemRequestStrategy::FILE; + request.message.renderer_item_index = element_index; + request.message.renderer_item_offset = element_offset; + request.message.size = size; + request.message.handle_index = segment_index; + request.message.handle_offset = segment_offset; + + requests->push_back(request); + builder->AppendFutureFile(segment_offset, size); + current_item_index++; + } + + void VisitNonBytesSegment(const DataElement& element, size_t element_index) { + builder->AppendIPCDataElement(element); + current_item_index++; + } + + void Done() {} + + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; + BlobDataBuilder* builder; + + size_t current_item_index; +}; + +// This class handles the logic of storing memory that is transported as +// consolidated shared memory. +class SharedMemoryStorageStrategy { + public: + SharedMemoryStorageStrategy( + size_t max_segment_size, + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* + requests, + BlobDataBuilder* builder) + : requests(requests), + max_segment_size(max_segment_size), + builder(builder), + current_item_size(0), + current_item_index(0) {} + ~SharedMemoryStorageStrategy() {} + + void VisitBytesSegment(size_t element_index, + uint64_t element_offset, + size_t segment_index, + uint64_t segment_offset, + uint64_t size) { + if (current_item_size + size > max_segment_size) { + builder->AppendFutureData(current_item_size); + current_item_index++; + current_item_size = 0; + } + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = current_item_index; + request.browser_item_offset = current_item_size; + request.message.request_number = requests->size(); + request.message.transport_strategy = + IPCBlobItemRequestStrategy::SHARED_MEMORY; + request.message.renderer_item_index = element_index; + request.message.renderer_item_offset = element_offset; + request.message.size = size; + request.message.handle_index = segment_index; + request.message.handle_offset = segment_offset; + + requests->push_back(request); + current_item_size += size; + } + + void VisitNonBytesSegment(const DataElement& element, size_t element_index) { + if (current_item_size != 0) { + builder->AppendFutureData(current_item_size); + current_item_index++; + } + builder->AppendIPCDataElement(element); + current_item_index++; + current_item_size = 0; + } + + void Done() { + if (current_item_size != 0) { + builder->AppendFutureData(current_item_size); + } + } + + std::vector<BlobAsyncTransportStrategy::RendererMemoryItemRequest>* requests; + + size_t max_segment_size; + BlobDataBuilder* builder; + size_t current_item_size; + uint64_t current_item_index; +}; + +// This iterates of the data elements and segments the 'bytes' data into +// the smallest number of segments given the max_segment_size. +// The callback describes either: +// * A non-memory item +// * A partition of a bytes element which will be populated into a given +// segment and segment offset. +// More specifically, we split each |element| into one or more |segments| of a +// max_size, invokes the strategy to determine the request to make for each +// |segment| produced. A |segment| can also span multiple |elements|. +// Assumptions: All memory items are consolidated. As in, there are no two +// 'bytes' items next to eachother. +template <typename Visitor> +void ForEachWithSegment(const std::vector<DataElement>& elements, + uint64_t max_segment_size, + Visitor* visitor) { + DCHECK_GT(max_segment_size, 0ull); + size_t segment_index = 0; + uint64_t segment_offset = 0; + size_t elements_length = elements.size(); + for (size_t element_index = 0; element_index < elements_length; + ++element_index) { + const auto& element = elements.at(element_index); + DataElement::Type type = element.type(); + if (!IsBytes(type)) { + visitor->VisitNonBytesSegment(element, element_index); + continue; + } + uint64_t element_memory_left = element.length(); + uint64_t element_offset = 0; + while (element_memory_left > 0) { + if (segment_offset == max_segment_size) { + ++segment_index; + segment_offset = 0; + } + uint64_t memory_writing = + std::min(max_segment_size - segment_offset, element_memory_left); + visitor->VisitBytesSegment(element_index, element_offset, segment_index, + segment_offset, memory_writing); + element_memory_left -= memory_writing; + segment_offset += memory_writing; + element_offset += memory_writing; + } + } + visitor->Done(); +} +} // namespace + +BlobAsyncTransportStrategy::RendererMemoryItemRequest:: + RendererMemoryItemRequest() + : browser_item_index(0), browser_item_offset(0), received(false) {} + +BlobAsyncTransportStrategy::BlobAsyncTransportStrategy() + : error_(BlobAsyncTransportStrategy::ERROR_NONE), total_bytes_size_(0) {} + +BlobAsyncTransportStrategy::~BlobAsyncTransportStrategy() {} + +// if total_blob_size > |memory_available| (say 400MB) +// Request all data in files +// (Segment all of the existing data into +// file blocks, of <= |max_file_size|) +// else if total_blob_size > |max_ipc_memory_size| (say 150KB) +// Request all data in shared memory +// (Segment all of the existing data into +// shared memory blocks, of <= |max_shared_memory_size|) +// else +// Request all data to be sent over IPC +void BlobAsyncTransportStrategy::Initialize( + size_t max_ipc_memory_size, + size_t max_shared_memory_size, + size_t max_file_size, + uint64_t disk_space_left, + size_t memory_available, + const std::string& uuid, + const std::vector<DataElement>& blob_item_infos) { + DCHECK(handle_sizes_.empty()); + DCHECK(requests_.empty()); + DCHECK(!builder_.get()); + builder_.reset(new BlobDataBuilder(uuid)); + error_ = BlobAsyncTransportStrategy::ERROR_NONE; + + size_t memory_items = 0; + base::CheckedNumeric<uint64_t> total_size_checked = 0; + for (const auto& info : blob_item_infos) { + if (!IsBytes(info.type())) { + continue; + } + total_size_checked += info.length(); + ++memory_items; + } + + if (!total_size_checked.IsValid()) { + DVLOG(1) << "Impossible total size of all memory elements."; + error_ = BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS; + return; + } + + total_bytes_size_ = total_size_checked.ValueOrDie(); + + // See if we have enough memory. + if (total_bytes_size_ > + disk_space_left + static_cast<uint64_t>(memory_available)) { + error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; + return; + } + + // If we're more than the available memory, then we're going straight to disk. + if (total_bytes_size_ > memory_available) { + if (total_bytes_size_ > disk_space_left) { + error_ = BlobAsyncTransportStrategy::ERROR_TOO_LARGE; + return; + } + ComputeHandleSizes(total_bytes_size_, max_file_size, &handle_sizes_); + FileStorageStrategy strategy(&requests_, builder_.get()); + ForEachWithSegment(blob_item_infos, static_cast<uint64_t>(max_file_size), + &strategy); + return; + } + + if (total_bytes_size_ > max_ipc_memory_size) { + // Note: The size must be <= std::numeric_limits<size_t>::max(). Otherwise + // we are guarenteed to be caught by the if statement above, + // |total_bytes_size_ > memory_available|. + ComputeHandleSizes(total_bytes_size_, max_shared_memory_size, + &handle_sizes_); + SharedMemoryStorageStrategy strategy(max_shared_memory_size, &requests_, + builder_.get()); + ForEachWithSegment(blob_item_infos, + static_cast<uint64_t>(max_shared_memory_size), + &strategy); + return; + } + + // Since they can all fit in IPC memory, we don't need to segment anything, + // and just request them straight in IPC. + size_t items_length = blob_item_infos.size(); + for (size_t i = 0; i < items_length; i++) { + const auto& info = blob_item_infos.at(i); + if (!IsBytes(info.type())) { + builder_->AppendIPCDataElement(info); + continue; + } + BlobAsyncTransportStrategy::RendererMemoryItemRequest request; + request.browser_item_index = i; + request.browser_item_offset = 0; + request.message.request_number = requests_.size(); + request.message.transport_strategy = IPCBlobItemRequestStrategy::IPC; + request.message.renderer_item_index = i; + request.message.renderer_item_offset = 0; + request.message.size = info.length(); + requests_.push_back(request); + builder_->AppendFutureData(info.length()); + } +} + +/* static */ +bool BlobAsyncTransportStrategy::ShouldBeShortcut( + const std::vector<DataElement>& elements, + size_t memory_available) { + base::CheckedNumeric<size_t> shortcut_bytes = 0; + for (const auto& element : elements) { + DataElement::Type type = element.type(); + if (type == DataElement::TYPE_BYTES_DESCRIPTION) { + return false; + } + if (type == DataElement::TYPE_BYTES) { + shortcut_bytes += element.length(); + if (!shortcut_bytes.IsValid()) { + return false; + } + } + } + return shortcut_bytes.ValueOrDie() <= memory_available; +} + +/* static */ +void BlobAsyncTransportStrategy::ComputeHandleSizes( + uint64_t total_memory_size, + size_t max_segment_size, + std::vector<size_t>* segment_sizes) { + size_t total_max_segments = + static_cast<size_t>(total_memory_size / max_segment_size); + bool has_extra_segment = (total_memory_size % max_segment_size) > 0; + segment_sizes->reserve(total_max_segments + (has_extra_segment ? 1 : 0)); + segment_sizes->insert(segment_sizes->begin(), total_max_segments, + max_segment_size); + if (has_extra_segment) { + segment_sizes->push_back(total_memory_size % max_segment_size); + } +} + +} // namespace storage
diff --git a/storage/browser/blob/blob_async_transport_strategy.h b/storage/browser/blob/blob_async_transport_strategy.h new file mode 100644 index 0000000..fe8d3743 --- /dev/null +++ b/storage/browser/blob/blob_async_transport_strategy.h
@@ -0,0 +1,123 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_ +#define STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_ + +#include <map> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "storage/browser/blob/blob_data_builder.h" +#include "storage/browser/storage_browser_export.h" +#include "storage/common/blob_storage/blob_item_bytes_request.h" +#include "storage/common/data_element.h" + +namespace storage { + +// This class computes and stores the strategy for asynchronously transporting +// memory from the renderer to the browser. We take memory constraints of our +// system and the description of a blob, and figure out: +// 1) How to store the blob data in the browser process: in memory or on disk. +// 2) How to transport the data from the renderer: ipc payload, shared memory, +// or file handles. +// We then generate data requests for that blob's memory and seed a +// BlobDataBuilder for storing that data. +// +// Note: This class does not compute requests by using the 'shortcut' method, +// where the data is already present in the blob description, and will +// always give the caller the full strategy for requesting all data from +// the renderer. +class STORAGE_EXPORT BlobAsyncTransportStrategy { + public: + enum Error { + ERROR_NONE = 0, + ERROR_TOO_LARGE, // This item can't fit in disk or memory + ERROR_INVALID_PARAMS + }; + + struct RendererMemoryItemRequest { + RendererMemoryItemRequest(); + // This is the index of the item in the builder on the browser side. + size_t browser_item_index; + // Note: For files this offset should always be 0, as the file offset in + // segmentation is handled by the handle_offset in the message. This + // offset is used for populating a chunk when the data comes back to + // the browser. + size_t browser_item_offset; + BlobItemBytesRequest message; + bool received; + }; + + BlobAsyncTransportStrategy(); + virtual ~BlobAsyncTransportStrategy(); + + // This call does the computation to create the requests and builder for the + // blob given the memory constraints and blob description. |memory_available| + // is the total amount of memory we can offer for storing blobs. + // This method can only be called once. + void Initialize(size_t max_ipc_memory_size, + size_t max_shared_memory_size, + size_t max_file_size, + uint64_t disk_space_left, + size_t memory_available, + const std::string& uuid, + const std::vector<DataElement>& blob_item_infos); + + // The sizes of the handles being used (by handle index) in the async + // operation. This is used for both files or shared memory, as their use is + // mutually exclusive. + const std::vector<size_t>& handle_sizes() const { return handle_sizes_; } + + // The requests for memory, segmented as described above, along with their + // destination browser indexes and offsets. + const std::vector<RendererMemoryItemRequest>& requests() const { + return requests_; + } + + // Marks the request at the given request number as recieved. + void MarkRequestAsReceived(size_t request_num) { + DCHECK_LT(request_num, requests_.size()); + requests_[request_num].received = true; + } + + // A BlobDataBuilder which can be used to construct the Blob in the + // BlobStorageContext object after: + // * The bytes items from AppendFutureData are populated by + // PopulateFutureData. + // * The temporary files from AppendFutureFile are populated by + // PopulateFutureFile. + BlobDataBuilder* blob_builder() { return builder_.get(); } + + // The total bytes size of memory items in the blob. + uint64_t total_bytes_size() const { return total_bytes_size_; } + + Error error() const { return error_; } + + static bool ShouldBeShortcut(const std::vector<DataElement>& items, + size_t memory_available); + + private: + static void ComputeHandleSizes(uint64_t total_memory_size, + size_t max_segment_size, + std::vector<size_t>* segment_sizes); + + Error error_; + + // We use the same vector for shared memory handle sizes and file handle sizes + // because we only use one for any strategy. The size of the handles is capped + // by the |max_file_size| argument in Initialize, so we can just use size_t. + std::vector<size_t> handle_sizes_; + + uint64_t total_bytes_size_; + std::vector<RendererMemoryItemRequest> requests_; + scoped_ptr<BlobDataBuilder> builder_; + + DISALLOW_COPY_AND_ASSIGN(BlobAsyncTransportStrategy); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_BLOB_BLOB_ASYNC_TRANSPORT_STRATEGY_H_
diff --git a/storage/browser/blob/blob_data_builder.cc b/storage/browser/blob/blob_data_builder.cc index 2ebfe89..69d9773 100644 --- a/storage/browser/blob/blob_data_builder.cc +++ b/storage/browser/blob/blob_data_builder.cc
@@ -12,6 +12,9 @@ namespace storage { +const char BlobDataBuilder::kAppendFutureFileTemporaryFileName[] = + "kFakeFilenameToBeChangedByPopulateFutureFile"; + BlobDataBuilder::BlobDataBuilder(const std::string& uuid) : uuid_(uuid) { } BlobDataBuilder::~BlobDataBuilder() { @@ -65,6 +68,7 @@ const char* data, size_t offset, size_t length) { + DCHECK_LT(index, items_.size()); DCHECK(data); DataElement* element = items_.at(index)->data_element_ptr(); @@ -93,6 +97,40 @@ return true; } +size_t BlobDataBuilder::AppendFutureFile(uint64_t offset, uint64_t length) { + CHECK_NE(length, 0ull); + scoped_ptr<DataElement> element(new DataElement()); + element->SetToFilePathRange(base::FilePath::FromUTF8Unsafe(std::string( + kAppendFutureFileTemporaryFileName)), + offset, length, base::Time()); + items_.push_back(new BlobDataItem(element.Pass())); + return items_.size() - 1; +} + +bool BlobDataBuilder::PopulateFutureFile( + size_t index, + const scoped_refptr<ShareableFileReference>& file_reference, + const base::Time& expected_modification_time) { + DCHECK_LT(index, items_.size()); + DataElement* old_element = items_.at(index)->data_element_ptr(); + + if (old_element->type() != DataElement::TYPE_FILE) { + DVLOG(1) << "Invalid item type."; + return false; + } else if (old_element->path().AsUTF8Unsafe() != + std::string(kAppendFutureFileTemporaryFileName)) { + DVLOG(1) << "Item not created by AppendFutureFile"; + return false; + } + uint64_t length = old_element->length(); + uint64_t offset = old_element->offset(); + scoped_ptr<DataElement> element(new DataElement()); + element->SetToFilePathRange(file_reference->path(), offset, length, + expected_modification_time); + items_[index] = new BlobDataItem(element.Pass(), file_reference); + return true; +} + void BlobDataBuilder::AppendFile(const base::FilePath& file_path, uint64_t offset, uint64_t length,
diff --git a/storage/browser/blob/blob_data_builder.h b/storage/browser/blob/blob_data_builder.h index 8627ebaf..f075c21 100644 --- a/storage/browser/blob/blob_data_builder.h +++ b/storage/browser/blob/blob_data_builder.h
@@ -23,11 +23,16 @@ namespace storage { class BlobStorageContext; +class ShareableFileReference; class STORAGE_EXPORT BlobDataBuilder { public: using DataHandle = BlobDataItem::DataHandle; + // This is the filename used for the temporary file items added by + // AppendFutureFile. + const static char kAppendFutureFileTemporaryFileName[]; + explicit BlobDataBuilder(const std::string& uuid); ~BlobDataBuilder(); @@ -49,8 +54,7 @@ // Adds an item that is flagged for future data population. The memory is not // allocated until the first call to PopulateFutureData. Returns the index of - // the item (to be used in PopulateFutureData). - // Length cannot be 0. + // the item (to be used in PopulateFutureData). |length| cannot be 0. size_t AppendFutureData(size_t length); // Populates a part of an item previously allocated with AppendFutureData. @@ -65,6 +69,22 @@ size_t offset, size_t length); + // Adds an item that is flagged for future data population. Use + // 'PopulateFutureFile' to set the file path and expected modification time + // of this file. Returns the index of the item (to be used in + // PopulateFutureFile). The temporary filename used by this method is + // kAppendFutureFileTemporaryFileName. |length| cannot be 0. + size_t AppendFutureFile(uint64_t offset, uint64_t length); + + // Populates a part of an item previously allocated with AppendFutureFile. + // Returns true if: + // * The item was created by using AppendFutureFile and + // * The filepath is valid. + bool PopulateFutureFile( + size_t index, + const scoped_refptr<ShareableFileReference>& file_reference, + const base::Time& expected_modification_time); + // You must know the length of the file, you cannot use kuint64max to specify // the whole file. This method creates a ShareableFileReference to the given // file, which is stored in this builder.
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc index 7114696..27db3cf 100644 --- a/storage/browser/blob/blob_storage_context.cc +++ b/storage/browser/blob/blob_storage_context.cc
@@ -93,32 +93,38 @@ } scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( - BlobDataBuilder* external_builder) { + const BlobDataBuilder& external_builder) { TRACE_EVENT0("Blob", "Context::AddFinishedBlob"); - StartBuildingBlob(external_builder->uuid_); - BlobMap::iterator found = blob_map_.find(external_builder->uuid_); + StartBuildingBlob(external_builder.uuid_); + BlobMap::iterator found = blob_map_.find(external_builder.uuid_); DCHECK(found != blob_map_.end()); BlobMapEntry* entry = found->second; InternalBlobData::Builder* target_blob_builder = entry->data_builder.get(); DCHECK(target_blob_builder); target_blob_builder->set_content_disposition( - external_builder->content_disposition_); - for (const auto& blob_item : external_builder->items_) { - if (!AppendAllocatedBlobItem(external_builder->uuid_, blob_item, + external_builder.content_disposition_); + for (const auto& blob_item : external_builder.items_) { + if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item, target_blob_builder)) { BlobEntryExceededMemory(entry); break; } } - FinishBuildingBlob(external_builder->uuid_, external_builder->content_type_); + FinishBuildingBlob(external_builder.uuid_, external_builder.content_type_); scoped_ptr<BlobDataHandle> handle = - GetBlobDataFromUUID(external_builder->uuid_); - DecrementBlobRefCount(external_builder->uuid_); + GetBlobDataFromUUID(external_builder.uuid_); + DecrementBlobRefCount(external_builder.uuid_); return handle.Pass(); } +scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( + const BlobDataBuilder* builder) { + DCHECK(builder); + return AddFinishedBlob(*builder); +} + bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url, const std::string& uuid) { DCHECK(!BlobUrlHasRef(blob_url));
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h index cf73c8a2..eba8abe 100644 --- a/storage/browser/blob/blob_storage_context.h +++ b/storage/browser/blob/blob_storage_context.h
@@ -55,7 +55,10 @@ // To cleanly use a builder multiple times, please call Clone() on the // builder, or even better for memory savings, clear the builder and append // the previously constructed blob. - scoped_ptr<BlobDataHandle> AddFinishedBlob(BlobDataBuilder* builder); + scoped_ptr<BlobDataHandle> AddFinishedBlob(const BlobDataBuilder& builder); + + // Deprecated, use const ref version above. + scoped_ptr<BlobDataHandle> AddFinishedBlob(const BlobDataBuilder* builder); // Useful for coining blob urls from within the browser process. bool RegisterPublicBlobURL(const GURL& url, const std::string& uuid);
diff --git a/storage/common/data_element.h b/storage/common/data_element.h index 0145308..8376751b 100644 --- a/storage/common/data_element.h +++ b/storage/common/data_element.h
@@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/files/file_path.h" +#include "base/gtest_prod_util.h" #include "base/logging.h" #include "base/time/time.h" #include "storage/common/storage_common_export.h" @@ -131,6 +132,7 @@ void SetToDiskCacheEntryRange(uint64 offset, uint64 length); private: + FRIEND_TEST_ALL_PREFIXES(BlobAsyncTransportStrategyTest, TestInvalidParams); friend STORAGE_COMMON_EXPORT void PrintTo(const DataElement& x, ::std::ostream* os); Type type_;
diff --git a/storage/storage_browser.gyp b/storage/storage_browser.gyp index 3f4b7ea..87a1186 100644 --- a/storage/storage_browser.gyp +++ b/storage/storage_browser.gyp
@@ -25,6 +25,10 @@ ], 'defines': ['STORAGE_BROWSER_IMPLEMENTATION'], 'sources': [ + 'browser/blob/blob_async_builder_host.cc', + 'browser/blob/blob_async_builder_host.h', + 'browser/blob/blob_async_transport_strategy.cc', + 'browser/blob/blob_async_transport_strategy.h', 'browser/blob/blob_data_builder.cc', 'browser/blob/blob_data_builder.h', 'browser/blob/blob_data_handle.cc',
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java index f28f21d..2b6e6a1a 100644 --- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java +++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
@@ -4,15 +4,12 @@ package org.chromium.sync.test.util; -import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; - import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; -import android.os.Handler; import org.chromium.base.Callback; import org.chromium.base.Log; @@ -37,9 +34,6 @@ * Currently, this implementation supports adding and removing accounts, handling credentials * (including confirming them), and handling of dummy auth tokens. * - * If you want the MockAccountManager to popup an activity for granting/denying access to an - * authtokentype for a given account, use prepareGrantAppPermission(...). - * * If you want to auto-approve a given authtokentype, use addAccountHolderExplicitly(...) with * an AccountHolder you have built with hasBeenAccepted("yourAuthTokenType", true). * @@ -50,21 +44,10 @@ private static final String TAG = "MockAccountManager"; - private static final long WAIT_TIME_FOR_GRANT_BROADCAST_MS = scaleTimeout(20000); - - static final String MUTEX_WAIT_ACTION = - "org.chromium.sync.test.util.MockAccountManager.MUTEX_WAIT_ACTION"; - protected final Context mContext; - private final Context mTestContext; - private final Set<AccountHolder> mAccounts; - private final Handler mMainHandler; - - private final SingleThreadedExecutor mExecutor; - // Tracks the number of in-progress getAccountsByType() tasks so that tests can wait for // their completion. private final ZeroCounter mGetAccountsTaskCounter; @@ -72,11 +55,6 @@ @VisibleForTesting public MockAccountManager(Context context, Context testContext, Account... accounts) { mContext = context; - // The manifest that is backing testContext needs to provide the - // MockGrantCredentialsPermissionActivity. - mTestContext = testContext; - mMainHandler = new Handler(mContext.getMainLooper()); - mExecutor = new SingleThreadedExecutor(); mGetAccountsTaskCounter = new ZeroCounter(); mAccounts = new HashSet<AccountHolder>(); if (accounts != null) {
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java deleted file mode 100644 index bbc4385c8..0000000 --- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockGrantCredentialsPermissionActivity.java +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.sync.test.util; - -import android.app.Activity; - -/** - * TODO(knn): Remove this after downstream references have been removed. - */ -public class MockGrantCredentialsPermissionActivity extends Activity { -}
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 7a399207..7d462d0b 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -437,9 +437,6 @@ "test": "mojo_system_unittests" }, { - "test": "nacl_helper_nonsfi_unittests" - }, - { "swarming": { "can_use_on_swarming_builders": true }, @@ -5705,7 +5702,7 @@ { "args": [ "--site-per-process", - "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionViewTest.*:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra" + "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra" ], "test": "browser_tests" }, @@ -5736,7 +5733,7 @@ { "args": [ "--site-per-process", - "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionViewTest.*:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra" + "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra" ], "test": "browser_tests" },
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json index 16112d1..5d502d0 100644 --- a/testing/buildbot/trybot_analyze_config.json +++ b/testing/buildbot/trybot_analyze_config.json
@@ -43,7 +43,6 @@ "third_party/hunspell_dictionaries/.*", "third_party/zlib/google/test/data/.*", "tools/clang/scripts/update.py", - "tools/clang/scripts/update.sh", "tools/mb/.*", "tools/metrics/histograms/histograms.xml", "tools/perf/.*",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index ab92481..c211067 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -83,7 +83,6 @@ crbug.com/465126 imported/gecko/variables/variable-declaration-24.html [ Failure ] crbug.com/465126 imported/gecko/variables/variable-declaration-25.html [ Failure ] -crbug.com/465126 imported/gecko/variables/variable-supports-13.html [ Failure ] crbug.com/465126 imported/gecko/variables/variable-external-font-face-01.html [ Failure ] crbug.com/280342 [ Linux Win ] http/tests/media/progress-events-generated-correctly.html [ Failure ] @@ -93,6 +92,7 @@ crbug.com/520736 [ Win7 ] media/W3C/video/networkState/networkState_during_progress.html [ Failure Pass ] crbug.com/563650 inspector/elements/css-rule-hover-highlights-selectors.html [ Pass Failure ] + crbug.com/522641 inspector/elements/styles-4/styles-update-links.html [ Pass Timeout ] crbug.com/522645 [ Linux ] virtual/android/fullscreen/video-fixed-background.html [ Failure Pass ] crbug.com/522646 http/tests/media/encrypted-media/encrypted-media-encrypted-event-different-origin.html [ Pass Slow ] @@ -104,7 +104,6 @@ crbug.com/521855 transitions/cancel-and-start-new.html [ Failure Pass ] crbug.com/521853 [ Win ] http/tests/inspector/search/sources-search-scope.html [ Failure Pass ] crbug.com/521084 animations/additive-transform-animations.html [ Pass Timeout ] -crbug.com/521085 fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html [ Crash Pass ] crbug.com/521086 fast/cookies/cookies-disabled-in-data-url.html [ Crash Pass Timeout ] crbug.com/521089 [ Precise ] fast/preloader/image.html [ Failure Pass ] crbug.com/521090 [ Mac Win ] http/tests/history/post-replace-state-reload.html [ Crash Failure Pass ] @@ -320,6 +319,7 @@ crbug.com/498539 [ Win7 ] inspector/elements/styles-3/selector-list.html [ Failure Pass ] crbug.com/498539 [ Win7 Debug ] inspector/elements/styles-3/styles-computed-trace.html [ Crash Pass ] crbug.com/498539 [ Win7 ] inspector/elements/styles-4/styles-update-from-js.html [ Crash Pass ] +crbug.com/565059 [ Debug ] inspector/console/console-uncaught-promise.html [ Crash Pass ] crbug.com/248938 [ Win Debug ] virtual/threaded/animations/transition-and-animation-2.html [ Timeout ] @@ -518,6 +518,15 @@ crbug.com/542660 imported/web-platform-tests/html/semantics/text-level-semantics/the-bdi-element/bdi-paragraph-level-container.html [ Failure ] crbug.com/542660 imported/web-platform-tests/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html [ Failure ] +# Ref tests that pass but causes 1px diff on images. +crbug.com/391260 [ Win ] fast/text/international/dir-isolation/dir-isolation-002c.html [ Failure ] +crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-006a.html [ Failure ] +crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-006b.html [ Failure ] +crbug.com/391260 [ Mac Win ] fast/text/international/dir-isolation/dir-isolation-006c.html [ Failure ] +crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009a.html [ Failure ] +crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009b.html [ Failure ] +crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009c.html [ Failure ] + # Ref tests that needs investigation. crbug.com/404597 [ Mac ] fast/css3-text/css3-text-justify/text-justify-crash.html [ Failure ] crbug.com/404597 fast/forms/long-text-in-input.html [ Failure ] @@ -1104,7 +1113,6 @@ crbug.com/532469 http/tests/security/cross-frame-access-custom.html [ NeedsManualRebaseline ] crbug.com/521730 [ Win10 ] compositing/plugins/invalidate_rect.html [ Crash ] -crbug.com/521730 [ Win10 ] plugins/mouse-click-plugin-clears-selection.html [ Crash ] crbug.com/521730 [ Win10 ] plugins/windowless_plugin_paint_test.html [ Crash ] crbug.com/521730 [ Win10 ] fast/text/shaping/same-script-different-lang.html [ Failure ] @@ -1198,7 +1206,8 @@ crbug.com/521730 [ Win10 ] fast/css/line-height-determined-by-primary-font.html [ Failure ] crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-l10n.html [ Failure ] crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-pseudo-elements.html [ Failure ] -crbug.com/521730 [ Win10 ] fast/forms/search/search-appearance-basic.html [ Failure ] +# TODO(fmalita): re-enable after http://crrev.com/1410733003 +# crbug.com/521730 [ Win10 ] fast/forms/search/search-appearance-basic.html [ Failure ] crbug.com/521730 [ Win10 ] fast/inline/justify-emphasis-inline-box.html [ Failure ] crbug.com/521730 [ Win10 ] fast/ruby/nested-ruby.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text-autosizing/display-type-change.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index d06f3a1..d70b2caf 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -22,6 +22,11 @@ }, { "prefix": "threaded", + "base": "fast/compositorworker", + "args": ["--enable-threaded-compositing"] + }, + { + "prefix": "threaded", "base": "compositing/webgl", "args": ["--enable-threaded-compositing"] },
diff --git a/third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html b/third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html new file mode 100644 index 0000000..8d9a78d --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html
@@ -0,0 +1,12 @@ +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<div id="target"></div> +<script> +test(() => { + target.style.left = '100px'; + var animation = target.animate([{easing: 'steps(2, start)'}, {left: '200px'}], 1000); + animation.pause(); + animation.currentTime = 0; + assert_equals(getComputedStyle(target).left, '150px'); +}, 'Neutral keyframes should be able to specify their own keyframe timing function.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js b/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js index 42dd313..d9201d0 100644 --- a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js +++ b/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js
@@ -135,7 +135,7 @@ function setState(bindings, targets, property, state) { if (state.inherited) { var parent = targets[0].parentElement; - console.assert(targets.every(function(target) { return target.parentElement === parent; })); + console.assert(targets.every(target => target.parentElement === parent)); bindings.setValue(parent, property, state.inherited); } if (state.underlying) { @@ -170,22 +170,22 @@ return keyframes; } -function startPausedAnimations(targets, keyframes, fractions) { +function createPausedAnimations(targets, keyframes, fractions) { console.assert(targets.length == fractions.length); - for (var i = 0; i < targets.length; i++) { - var target = targets[i]; + return targets.map((target, i) => { var fraction = fractions[i]; console.assert(fraction >= 0 && fraction < 1); var animation = target.animate(keyframes, 1); - animation.currentTime = fraction; animation.pause(); - } + animation.currentTime = fraction; + return animation; + }); } function runPendingResponsiveTests() { - return new Promise(function(resolve) { + return new Promise(resolve => { var stateTransitionTests = []; - pendingResponsiveTests.forEach(function(responsiveTest) { + pendingResponsiveTests.forEach(responsiveTest => { var options = responsiveTest.options; var bindings = responsiveTest.bindings; var property = options.property; @@ -197,7 +197,7 @@ var keyframes = createKeyframes(prefixedProperty, from, to); var stateTransitions = createStateTransitions(options.configurations); - stateTransitions.forEach(function(stateTransition) { + stateTransitions.forEach(stateTransition => { var before = stateTransition.before; var after = stateTransition.after; var container = bindings.createTargetContainer(document.body); @@ -205,8 +205,21 @@ var expectationTargets = createTargets(bindings, after.expect.length, container); setState(bindings, targets, property, before.state); - startPausedAnimations(targets, keyframes, after.expect.map(function(expectation) { return expectation.at; })); + var animations = createPausedAnimations(targets, keyframes, after.expect.map(expectation => expectation.at)); stateTransitionTests.push({ + // TODO(alancutter): Make SVG animations responsive when their interpolation fractions haven't changed. + wiggleFractionHack() { + return new Promise(resolve => { + animations.forEach(animation => { + var currentTime = animation.currentTime; + animation.currentTime = 1; + requestAnimationFrame(() => { + animation.currentTime = currentTime; + }); + }); + requestAnimationFrame(resolve); + }); + }, applyStateTransition() { setState(bindings, targets, property, after.state); }, @@ -217,7 +230,7 @@ var expectationTarget = expectationTargets[i]; bindings.setValue(expectationTarget, property, expectation.is); var actual = bindings.getAnimatedValue(target, property); - test(function() { + test(() => { assert_equals(actual, bindings.getAnimatedValue(expectationTarget, property)); }, `Animation on property <${prefixedProperty}> from ${keyframeText(from)} to ${keyframeText(to)} with ${JSON.stringify(before.state)} changed to ${JSON.stringify(after.state)} at (${expectation.at}) is [${expectation.is}]`); } @@ -226,21 +239,25 @@ }); }); - for (var stateTransitionTest of stateTransitionTests) { - stateTransitionTest.applyStateTransition(); - } - - requestAnimationFrame(function() { + requestAnimationFrame(() => { for (var stateTransitionTest of stateTransitionTests) { - stateTransitionTest.assert(); + stateTransitionTest.applyStateTransition(); } - resolve(); + + Promise.all(stateTransitionTests.map(stateTransitionTest => stateTransitionTest.wiggleFractionHack())).then(() => { + requestAnimationFrame(() => { + for (var stateTransitionTest of stateTransitionTests) { + stateTransitionTest.assert(); + } + resolve(); + }); + }) }); }); } function loadScript(url) { - return new Promise(function(resolve) { + return new Promise(resolve => { var script = document.createElement('script'); script.src = url; script.onload = resolve; @@ -248,11 +265,11 @@ }); } -loadScript('../../resources/testharness.js').then(function() { +loadScript('../../resources/testharness.js').then(() => { return loadScript('../../resources/testharnessreport.js'); -}).then(function() { +}).then(() => { var asyncHandle = async_test('This test uses responsive-test.js.') - runPendingResponsiveTests().then(function() { + runPendingResponsiveTests().then(() => { asyncHandle.done(); }); });
diff --git a/third_party/WebKit/LayoutTests/canvas/resources/green-flash-at-50ms.svg b/third_party/WebKit/LayoutTests/canvas/resources/green-flash-at-50ms.svg new file mode 100644 index 0000000..f9099b7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/canvas/resources/green-flash-at-50ms.svg
@@ -0,0 +1,18 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> + <defs> + <style type="text/css"><![CDATA[ + #square { + fill: red; + -webkit-animation: keyframes 0.05s; + -webkit-animation-fill-mode: forwards; + -webkit-animation-timing-function: step-end; + } + @-webkit-keyframes keyframes { + 0% { fill: blue } + 99% { fill: blue } + 100% { fill: green } + } + ]]></style> + </defs> + <rect id="square" width="100" height="100" x="0" y="0"></rect> +</svg>
diff --git a/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern-expected.html b/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern-expected.html index 973820c..3536eba2 100644 --- a/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern-expected.html +++ b/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern-expected.html
@@ -1,11 +1,14 @@ <!DOCTYPE HTML> <html> <body> - Test for crbug.com/279445: createPattern should synchronously snapshot an animating image.<br/> - This test passes if there is a green square below.<br/> - <svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'> - <rect width='100' height='100' fill='green'/> - </svg> + Test for crbug.com/279445: createPattern should synchronously snapshot an animating image.<br/> + This test passes if there is a blue square below:<br/> + <svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'> + <rect width='100' height='100' fill='blue'/> + </svg><br/> + And a green square below:<br/> + <svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'> + <rect width='100' height='100' fill='green'/> + </svg> </body> </html> -
diff --git a/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern.html b/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern.html new file mode 100644 index 0000000..e23fa362 --- /dev/null +++ b/third_party/WebKit/LayoutTests/canvas/synchronous-create-pattern.html
@@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<script> +var canvas, context, pattern, image; + +function runTest() { + if (window.testRunner) + testRunner.waitUntilDone(); + + canvas = document.getElementById('canvas'); + context = canvas.getContext('2d'); + + // Initialize the canvas with orange. + context.fillStyle = '#FFA500'; + context.fillRect(0, 0, 100, 100); + + image = document.getElementById('image'); + image.setAttribute('src', 'resources/green-flash-at-50ms.svg'); + image.onload = function() { + pattern = context.createPattern(image, 'repeat'); + setTimeout(function() { drawPatternAndFinish(); }, 55); + } +} + +function drawPatternAndFinish() { + // Advance the image one more time to the last frame. + // The pattern should not be affected. + window.internals.advanceImageAnimation(image); + + context.fillStyle = pattern; + context.fillRect(0, 0, 200, 200); + + if (window.testRunner) + testRunner.notifyDone(); +} + +</script> +<body onload='runTest()'> + Test for crbug.com/279445: createPattern should synchronously snapshot an animating image.<br/> + This test passes if there is a blue square below:<br/> + <canvas id='canvas' width='100' height='100'></canvas><br/> + And a green square below:<br/> + <img id='image' width='100' height='100'> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-mac-expected.txt b/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-mac-expected.txt index 5c20a9c..89b53f0 100644 --- a/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-mac-expected.txt +++ b/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-mac-expected.txt
@@ -10,7 +10,7 @@ PASS LeftToRight on second and third words of "<b>hello world</b> webkit" PASS RightToLeft on second and third words of "<b>hello world</b> webkit" FAIL (due to the bug 44359) Natural on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world</span></span><span><span> webkit</span></span><span dir="rtl"><span dir="ltr"> rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world</span></span> webkit<span dir="rtl"><span dir="ltr"> rocks</span></span> -FAIL (due to the bug 44359) LeftToRight on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world</span></span><span><span style="unicode-bidi: embed;"> webkit</span></span><span dir="rtl"><span dir="ltr"> rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world</span></span><span style="unicode-bidi: embed;"> webkit</span><span dir="rtl"><span dir="ltr"> rocks</span></span> +FAIL (due to the bug 44359) LeftToRight on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world</span></span><span><span style="unicode-bidi: isolate;"> webkit</span></span><span dir="rtl"><span dir="ltr"> rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world</span></span><span style="unicode-bidi: isolate;"> webkit</span><span dir="rtl"><span dir="ltr"> rocks</span></span> FAIL (due to the bug 44359) RightToLeft on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world</span><span> webkit</span><span dir="ltr"> rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world</span> webkit<span dir="ltr"> rocks</span></span> PASS Natural on first word of "هنا يكتب النص العربي" PASS LeftToRight on first word of "هنا يكتب النص العربي"
diff --git a/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-win-expected.txt b/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-win-expected.txt index 7113f73..19e8054 100644 --- a/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-win-expected.txt +++ b/third_party/WebKit/LayoutTests/editing/style/make-text-writing-direction-inline-win-expected.txt
@@ -10,7 +10,7 @@ PASS LeftToRight on second and third words of "<b>hello world</b> webkit" PASS RightToLeft on second and third words of "<b>hello world</b> webkit" FAIL (due to the bug 44359) Natural on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world </span></span><span><span>webkit </span></span><span dir="rtl"><span dir="ltr">rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world </span></span>webkit <span dir="rtl"><span dir="ltr">rocks</span></span> -FAIL (due to the bug 44359) LeftToRight on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world </span></span><span><span style="unicode-bidi: embed;">webkit </span></span><span dir="rtl"><span dir="ltr">rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world </span></span><span style="unicode-bidi: embed;">webkit </span><span dir="rtl"><span dir="ltr">rocks</span></span> +FAIL (due to the bug 44359) LeftToRight on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world </span></span><span><span style="unicode-bidi: isolate;">webkit </span></span><span dir="rtl"><span dir="ltr">rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world </span></span><span style="unicode-bidi: isolate;">webkit </span><span dir="rtl"><span dir="ltr">rocks</span></span> FAIL (due to the bug 44359) RightToLeft on third word of "<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>" yielded <span dir="rtl">hello <span dir="ltr">world </span><span>webkit </span><span dir="ltr">rocks</span></span> but expected <span dir="rtl">hello <span dir="ltr">world </span>webkit <span dir="ltr">rocks</span></span> PASS Natural on first word of "هنا يكتب النص العربي" PASS LeftToRight on first word of "هنا يكتب النص العربي"
diff --git a/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-mac.js b/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-mac.js index cc19c77a..a51db60 100644 --- a/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-mac.js +++ b/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-mac.js
@@ -68,49 +68,49 @@ // left to right language modifyWritingDirection('hello world', selectFirstWord, 'Natural', 'hello world'); -modifyWritingDirection('hello world', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">hello</span> world'); -modifyWritingDirection('hello world', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">hello</span> world'); +modifyWritingDirection('hello world', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">hello</span> world'); +modifyWritingDirection('hello world', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">hello</span> world'); modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'Natural', '<b>hello world</b> webkit'); -modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'LeftToRight', '<b>hello<span style="unicode-bidi: embed;"> world</span></b><span style="unicode-bidi: embed;"> webkit</span>'); -modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'RightToLeft', '<b>hello<span style="unicode-bidi: embed; direction: rtl;"> world</span></b><span style="unicode-bidi: embed; direction: rtl;"> webkit</span>'); +modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'LeftToRight', '<b>hello<span style="unicode-bidi: isolate;"> world</span></b><span style="unicode-bidi: isolate;"> webkit</span>'); +modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'RightToLeft', '<b>hello<span style="unicode-bidi: isolate; direction: rtl;"> world</span></b><span style="unicode-bidi: isolate; direction: rtl;"> webkit</span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'Natural', '<span dir="rtl">hello <span dir="ltr">world</span></span> webkit<span dir="rtl"><span dir="ltr"> rocks</span></span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'LeftToRight', - '<span dir="rtl">hello <span dir="ltr">world</span></span><span style="unicode-bidi: embed;"> webkit</span><span dir="rtl"><span dir="ltr"> rocks</span></span>'); + '<span dir="rtl">hello <span dir="ltr">world</span></span><span style="unicode-bidi: isolate;"> webkit</span><span dir="rtl"><span dir="ltr"> rocks</span></span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'RightToLeft', '<span dir="rtl">hello <span dir="ltr">world</span> webkit<span dir="ltr"> rocks</span></span>'); // right to left language modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'Natural', 'هنا يكتب النص العربي'); -modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">هنا</span> يكتب النص العربي'); -modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">هنا</span> يكتب النص العربي'); +modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">هنا</span> يكتب النص العربي'); +modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">هنا</span> يكتب النص العربي'); modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'Natural', '<b>هنا يكتب</b> النص العربي'); -modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'LeftToRight', '<b>هنا<span style="unicode-bidi: embed;"> يكتب</span></b><span style="unicode-bidi: embed;"> النص</span> العربي'); -modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'RightToLeft', '<b>هنا<span style="unicode-bidi: embed; direction: rtl;"> يكتب</span></b><span style="unicode-bidi: embed; direction: rtl;"> النص</span> العربي'); +modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'LeftToRight', '<b>هنا<span style="unicode-bidi: isolate;"> يكتب</span></b><span style="unicode-bidi: isolate;"> النص</span> العربي'); +modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'RightToLeft', '<b>هنا<span style="unicode-bidi: isolate; direction: rtl;"> يكتب</span></b><span style="unicode-bidi: isolate; direction: rtl;"> النص</span> العربي'); modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'Natural', '<div dir="rtl">هنا يكتب النص العربي</div>'); -modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">هنا</span> يكتب النص العربي</div>'); -modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: embed;">هنا</span> يكتب النص العربي</div>'); +modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">هنا</span> يكتب النص العربي</div>'); +modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: isolate;">هنا</span> يكتب النص العربي</div>'); modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'Natural', '<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>'); -modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'LeftToRight', '<div dir="rtl"><b>هنا<span style="unicode-bidi: embed; direction: ltr;"> يكتب</span></b><span style="unicode-bidi: embed; direction: ltr;"> النص</span> العربي</div>'); -modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'RightToLeft', '<div dir="rtl"><b>هنا<span style="unicode-bidi: embed;"> يكتب</span></b><span style="unicode-bidi: embed;"> النص</span> العربي</div>'); +modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'LeftToRight', '<div dir="rtl"><b>هنا<span style="unicode-bidi: isolate; direction: ltr;"> يكتب</span></b><span style="unicode-bidi: isolate; direction: ltr;"> النص</span> العربي</div>'); +modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'RightToLeft', '<div dir="rtl"><b>هنا<span style="unicode-bidi: isolate;"> يكتب</span></b><span style="unicode-bidi: isolate;"> النص</span> العربي</div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'Natural', '<div dir="rtl">هنا <span dir="ltr">يكتب</span> النص<span dir="ltr"> العربي</span></div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'LeftToRight', - '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">هنا يكتب النص العربي</span></div>'); + '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">هنا يكتب النص العربي</span></div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'RightToLeft', - '<div dir="rtl">هنا <span dir="ltr">يكتب</span><span style="unicode-bidi: embed;"> النص</span><span dir="ltr"> العربي</span></div>'); + '<div dir="rtl">هنا <span dir="ltr">يكتب</span><span style="unicode-bidi: isolate;"> النص</span><span dir="ltr"> العربي</span></div>'); // bidirectional langauge modifyWritingDirection('写䏿–‡', selectFirstWord, 'Natural', '写䏿–‡'); -modifyWritingDirection('写䏿–‡', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">写</span>䏿–‡'); -modifyWritingDirection('写䏿–‡', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">写</span>䏿–‡'); +modifyWritingDirection('写䏿–‡', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">写</span>䏿–‡'); +modifyWritingDirection('写䏿–‡', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">写</span>䏿–‡'); modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'Natural', '<div dir="rtl">写䏿–‡</div>'); -modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">写</span>䏿–‡</div>'); -modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: embed;">写</span>䏿–‡</div>'); +modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">写</span>䏿–‡</div>'); +modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: isolate;">写</span>䏿–‡</div>'); document.body.removeChild(testContainer);
diff --git a/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-win.js b/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-win.js index 8d12e391..17ed903 100644 --- a/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-win.js +++ b/third_party/WebKit/LayoutTests/editing/style/script-tests/make-text-writing-direction-inline-win.js
@@ -68,49 +68,49 @@ // left to right language modifyWritingDirection('hello world', selectFirstWord, 'Natural', 'hello world'); -modifyWritingDirection('hello world', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">hello </span>world'); -modifyWritingDirection('hello world', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">hello </span>world'); +modifyWritingDirection('hello world', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">hello </span>world'); +modifyWritingDirection('hello world', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">hello </span>world'); modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'Natural', '<b>hello world</b> webkit'); -modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'LeftToRight', '<b>hello <span style="unicode-bidi: embed;">world</span></b><span style="unicode-bidi: embed;"> webkit</span>'); -modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'RightToLeft', '<b>hello <span style="unicode-bidi: embed; direction: rtl;">world</span></b><span style="unicode-bidi: embed; direction: rtl;"> webkit</span>'); +modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'LeftToRight', '<b>hello <span style="unicode-bidi: isolate;">world</span></b><span style="unicode-bidi: isolate;"> webkit</span>'); +modifyWritingDirection('<b>hello world</b> webkit', selectSecondAndThirdWords, 'RightToLeft', '<b>hello <span style="unicode-bidi: isolate; direction: rtl;">world</span></b><span style="unicode-bidi: isolate; direction: rtl;"> webkit</span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'Natural', '<span dir="rtl">hello <span dir="ltr">world </span></span>webkit <span dir="rtl"><span dir="ltr">rocks</span></span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'LeftToRight', - '<span dir="rtl">hello <span dir="ltr">world </span></span><span style="unicode-bidi: embed;">webkit </span><span dir="rtl"><span dir="ltr">rocks</span></span>'); + '<span dir="rtl">hello <span dir="ltr">world </span></span><span style="unicode-bidi: isolate;">webkit </span><span dir="rtl"><span dir="ltr">rocks</span></span>'); modifyWritingDirection('<span dir="rtl">hello <span dir="ltr">world webkit rocks</span></span>', selectThirdWord, 'RightToLeft', '<span dir="rtl">hello <span dir="ltr">world </span>webkit <span dir="ltr">rocks</span></span>'); // right to left language modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'Natural', 'هنا يكتب النص العربي'); -modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">هنا </span>يكتب النص العربي'); -modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">هنا </span>يكتب النص العربي'); +modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">هنا </span>يكتب النص العربي'); +modifyWritingDirection('هنا يكتب النص العربي', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">هنا </span>يكتب النص العربي'); modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'Natural', '<b>هنا يكتب</b> النص العربي'); -modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'LeftToRight', '<b>هنا <span style="unicode-bidi: embed;">يكتب</span></b><span style="unicode-bidi: embed;"> النص </span>العربي'); -modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'RightToLeft', '<b>هنا <span style="unicode-bidi: embed; direction: rtl;">يكتب</span></b><span style="unicode-bidi: embed; direction: rtl;"> النص </span>العربي'); +modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'LeftToRight', '<b>هنا <span style="unicode-bidi: isolate;">يكتب</span></b><span style="unicode-bidi: isolate;"> النص </span>العربي'); +modifyWritingDirection('<b>هنا يكتب</b> النص العربي', selectSecondAndThirdWords, 'RightToLeft', '<b>هنا <span style="unicode-bidi: isolate; direction: rtl;">يكتب</span></b><span style="unicode-bidi: isolate; direction: rtl;"> النص </span>العربي'); modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'Natural', '<div dir="rtl">هنا يكتب النص العربي</div>'); -modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">هنا </span>يكتب النص العربي</div>'); -modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: embed;">هنا </span>يكتب النص العربي</div>'); +modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">هنا </span>يكتب النص العربي</div>'); +modifyWritingDirection('<div dir="rtl">هنا يكتب النص العربي</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: isolate;">هنا </span>يكتب النص العربي</div>'); modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'Natural', '<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>'); -modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'LeftToRight', '<div dir="rtl"><b>هنا <span style="unicode-bidi: embed; direction: ltr;">يكتب</span></b><span style="unicode-bidi: embed; direction: ltr;"> النص </span>العربي</div>'); -modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'RightToLeft', '<div dir="rtl"><b>هنا <span style="unicode-bidi: embed;">يكتب</span></b><span style="unicode-bidi: embed;"> النص </span>العربي</div>'); +modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'LeftToRight', '<div dir="rtl"><b>هنا <span style="unicode-bidi: isolate; direction: ltr;">يكتب</span></b><span style="unicode-bidi: isolate; direction: ltr;"> النص </span>العربي</div>'); +modifyWritingDirection('<div dir="rtl"><b>هنا يكتب</b> النص العربي</div>', selectSecondAndThirdWords, 'RightToLeft', '<div dir="rtl"><b>هنا <span style="unicode-bidi: isolate;">يكتب</span></b><span style="unicode-bidi: isolate;"> النص </span>العربي</div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'Natural', '<div dir="rtl">هنا <span dir="ltr">يكتب </span>النص <span dir="ltr">العربي</span></div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'LeftToRight', - '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">هنا يكتب النص العربي</span></div>'); + '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">هنا يكتب النص العربي</span></div>'); modifyWritingDirection('<div dir="rtl">هنا <span dir="ltr">يكتب النص العربي</span></div>', selectThirdWord, 'RightToLeft', - '<div dir="rtl">هنا <span dir="ltr">يكتب </span><span style="unicode-bidi: embed;">النص </span><span dir="ltr">العربي</span></div>'); + '<div dir="rtl">هنا <span dir="ltr">يكتب </span><span style="unicode-bidi: isolate;">النص </span><span dir="ltr">العربي</span></div>'); // bidirectional langauge modifyWritingDirection('写䏿–‡', selectFirstWord, 'Natural', '写䏿–‡'); -modifyWritingDirection('写䏿–‡', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: embed;">写</span>䏿–‡'); -modifyWritingDirection('写䏿–‡', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: embed; direction: rtl;">写</span>䏿–‡'); +modifyWritingDirection('写䏿–‡', selectFirstWord, 'LeftToRight', '<span style="unicode-bidi: isolate;">写</span>䏿–‡'); +modifyWritingDirection('写䏿–‡', selectFirstWord, 'RightToLeft', '<span style="unicode-bidi: isolate; direction: rtl;">写</span>䏿–‡'); modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'Natural', '<div dir="rtl">写䏿–‡</div>'); -modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: embed; direction: ltr;">写</span>䏿–‡</div>'); -modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: embed;">写</span>䏿–‡</div>'); +modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'LeftToRight', '<div dir="rtl"><span style="unicode-bidi: isolate; direction: ltr;">写</span>䏿–‡</div>'); +modifyWritingDirection('<div dir="rtl">写䏿–‡</div>', selectFirstWord, 'RightToLeft', '<div dir="rtl"><span style="unicode-bidi: isolate;">写</span>䏿–‡</div>'); document.body.removeChild(testContainer);
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/svg-as-mask-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/svg-as-mask-expected.png index 5a20b5b..2d1f09e 100644 --- a/third_party/WebKit/LayoutTests/fast/backgrounds/svg-as-mask-expected.png +++ b/third_party/WebKit/LayoutTests/fast/backgrounds/svg-as-mask-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed01-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed01-expected.png index 800b25d..3735b50 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed01-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed01-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed02-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed02-expected.png index d6dbe01e..ed5294c 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed02-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed02-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed03-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed03-expected.png index f34d901..49fd9ba2 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed03-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed03-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed04-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed04-expected.png index 6171f61..18ace50 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed04-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed04-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed05-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed05-expected.png index c8e9524..aaa74f4 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed05-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed05-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed06-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed06-expected.png index 2454409..5c100c9 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed06-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDashed06-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted01-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted01-expected.png index 771f8a6..23c3936 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted01-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted01-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted02-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted02-expected.png index bf08730..104aa331 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted02-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted02-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted03-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted03-expected.png index 68e6fb3..f19befb 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted03-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted03-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png index 1174d032..08ce7ec 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted06-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted06-expected.png index 651a4b36..1a143758 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted06-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted06-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules-expected.txt b/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules-expected.txt index 617bed0..779dea4 100644 --- a/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules-expected.txt
@@ -3,23 +3,23 @@ PASS styleOf("div", {}).direction is "ltr" FAIL styleOf("div", {}).unicodeBidi should be -webkit-isolate. Was normal. PASS styleOf("div", {"dir":"ltr"}).direction is "ltr" -PASS styleOf("div", {"dir":"ltr"}).unicodeBidi is "embed" +PASS styleOf("div", {"dir":"ltr"}).unicodeBidi is "isolate" PASS styleOf("div", {"dir":"rtl"}).direction is "rtl" -PASS styleOf("div", {"dir":"rtl"}).unicodeBidi is "embed" +PASS styleOf("div", {"dir":"rtl"}).unicodeBidi is "isolate" PASS styleOf("div", {"dir":"auto"}).direction is "ltr" PASS styleOf("div", {"dir":"auto"}).unicodeBidi is "isolate" PASS styleOf("div", {"dir":""}).direction is "ltr" -PASS styleOf("div", {"dir":""}).unicodeBidi is "embed" +PASS styleOf("div", {"dir":""}).unicodeBidi is "isolate" PASS styleOf("span", {}).direction is "ltr" PASS styleOf("span", {}).unicodeBidi is "normal" PASS styleOf("span", {"dir":"ltr"}).direction is "ltr" -PASS styleOf("span", {"dir":"ltr"}).unicodeBidi is "embed" +PASS styleOf("span", {"dir":"ltr"}).unicodeBidi is "isolate" PASS styleOf("span", {"dir":"rtl"}).direction is "rtl" -PASS styleOf("span", {"dir":"rtl"}).unicodeBidi is "embed" +PASS styleOf("span", {"dir":"rtl"}).unicodeBidi is "isolate" PASS styleOf("span", {"dir":"auto"}).direction is "ltr" PASS styleOf("span", {"dir":"auto"}).unicodeBidi is "isolate" PASS styleOf("span", {"dir":""}).direction is "ltr" -PASS styleOf("span", {"dir":""}).unicodeBidi is "embed" +PASS styleOf("span", {"dir":""}).unicodeBidi is "isolate" PASS styleOf("bdi", {}).direction is "ltr" PASS styleOf("bdi", {}).unicodeBidi is "isolate" PASS styleOf("bdi", {"dir":"ltr"}).direction is "ltr" @@ -53,23 +53,23 @@ PASS styleOf("textarea", {}).direction is "ltr" PASS styleOf("textarea", {}).unicodeBidi is "normal" PASS styleOf("textarea", {"dir":"ltr"}).direction is "ltr" -PASS styleOf("textarea", {"dir":"ltr"}).unicodeBidi is "embed" +PASS styleOf("textarea", {"dir":"ltr"}).unicodeBidi is "isolate" PASS styleOf("textarea", {"dir":"rtl"}).direction is "rtl" -PASS styleOf("textarea", {"dir":"rtl"}).unicodeBidi is "embed" +PASS styleOf("textarea", {"dir":"rtl"}).unicodeBidi is "isolate" PASS styleOf("textarea", {"dir":"auto"}).direction is "ltr" PASS styleOf("textarea", {"dir":"auto"}).unicodeBidi is "plaintext" PASS styleOf("textarea", {"dir":""}).direction is "ltr" -PASS styleOf("textarea", {"dir":""}).unicodeBidi is "embed" +PASS styleOf("textarea", {"dir":""}).unicodeBidi is "isolate" PASS styleOf("pre", {}).direction is "ltr" PASS styleOf("pre", {}).unicodeBidi is "normal" PASS styleOf("pre", {"dir":"ltr"}).direction is "ltr" -PASS styleOf("pre", {"dir":"ltr"}).unicodeBidi is "embed" +PASS styleOf("pre", {"dir":"ltr"}).unicodeBidi is "isolate" PASS styleOf("pre", {"dir":"rtl"}).direction is "rtl" -PASS styleOf("pre", {"dir":"rtl"}).unicodeBidi is "embed" +PASS styleOf("pre", {"dir":"rtl"}).unicodeBidi is "isolate" PASS styleOf("pre", {"dir":"auto"}).direction is "ltr" PASS styleOf("pre", {"dir":"auto"}).unicodeBidi is "plaintext" PASS styleOf("pre", {"dir":""}).direction is "ltr" -PASS styleOf("pre", {"dir":""}).unicodeBidi is "embed" +PASS styleOf("pre", {"dir":""}).unicodeBidi is "isolate" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules.html b/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules.html index 9d8ce0a..a78b14b 100644 --- a/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules.html +++ b/third_party/WebKit/LayoutTests/fast/css/default-bidi-css-rules.html
@@ -21,16 +21,16 @@ var tests = [ ['div', {}, 'ltr', '-webkit-isolate'], - ['div', {'dir': 'ltr'}, 'ltr', 'embed'], - ['div', {'dir': 'rtl'}, 'rtl', 'embed'], + ['div', {'dir': 'ltr'}, 'ltr', 'isolate'], + ['div', {'dir': 'rtl'}, 'rtl', 'isolate'], ['div', {'dir': 'auto'}, 'ltr', 'isolate'], - ['div', {'dir': ''}, 'ltr', 'embed'], + ['div', {'dir': ''}, 'ltr', 'isolate'], ['span', {}, 'ltr', 'normal'], - ['span', {'dir': 'ltr'}, 'ltr', 'embed'], - ['span', {'dir': 'rtl'}, 'rtl', 'embed'], + ['span', {'dir': 'ltr'}, 'ltr', 'isolate'], + ['span', {'dir': 'rtl'}, 'rtl', 'isolate'], ['span', {'dir': 'auto'}, 'ltr', 'isolate'], - ['span', {'dir': ''}, 'ltr', 'embed'], + ['span', {'dir': ''}, 'ltr', 'isolate'], ['bdi', {}, 'ltr', 'isolate'], ['bdi', {'dir': 'ltr'}, 'ltr', 'isolate'], @@ -51,16 +51,16 @@ ['bdo', {'dir': ''}, 'ltr', 'bidi-override'], ['textarea', {}, 'ltr', 'normal'], - ['textarea', {'dir': 'ltr'}, 'ltr', 'embed'], - ['textarea', {'dir': 'rtl'}, 'rtl', 'embed'], + ['textarea', {'dir': 'ltr'}, 'ltr', 'isolate'], + ['textarea', {'dir': 'rtl'}, 'rtl', 'isolate'], ['textarea', {'dir': 'auto'}, 'ltr', 'plaintext'], - ['textarea', {'dir': ''}, 'ltr', 'embed'], + ['textarea', {'dir': ''}, 'ltr', 'isolate'], ['pre', {}, 'ltr', 'normal'], - ['pre', {'dir': 'ltr'}, 'ltr', 'embed'], - ['pre', {'dir': 'rtl'}, 'rtl', 'embed'], + ['pre', {'dir': 'ltr'}, 'ltr', 'isolate'], + ['pre', {'dir': 'rtl'}, 'rtl', 'isolate'], ['pre', {'dir': 'auto'}, 'ltr', 'plaintext'], - ['pre', {'dir': ''}, 'ltr', 'embed'], + ['pre', {'dir': ''}, 'ltr', 'isolate'], ].forEach(function (test) { shouldBe('styleOf("' + test[0] + '", ' + JSON.stringify(test[1]) + ').direction', '"' + test[2] + '"'); container.innerHTML = '';
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/cycle-detection-is-order-independent.html b/third_party/WebKit/LayoutTests/fast/css/variables/cycle-detection-is-order-independent.html new file mode 100644 index 0000000..7c6f034 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/variables/cycle-detection-is-order-independent.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<style> +div { + width: 100px; + height: 100px; +} +#firstdiv { + --b: var(--b); + --a: var(--b, green); + background-color: var(--a,red); +} +#seconddiv { + --c: var(--c); + --d: var(--c, green); + background-color: var(--d,red); +} +</style> + +<div id=firstdiv></div> +<div id=seconddiv></div> + +<script> +test(function() { + assert_equals(getComputedStyle(firstdiv).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(seconddiv).backgroundColor, 'rgb(0, 128, 0)'); +}, 'custom property cycles are marked invalid in the same way, independent of ordering.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/tricky-cycle-cases.html b/third_party/WebKit/LayoutTests/fast/css/variables/tricky-cycle-cases.html new file mode 100644 index 0000000..cc56bf5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/variables/tricky-cycle-cases.html
@@ -0,0 +1,147 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<style> +div { + width: 400px; + height: 50px; + margin-bottom: 5px; +} + +#twocycleinfallback_a { + --a: var(--b, red); + --b: var(--not-defined, var(--a)); + background-color: orange; + background-color: var(--a, green); +} + +#twocycleinfallback_ra { + --b: var(--a, red); + --a: var(--not-defined, var(--b)); + background-color: orange; + background-color: var(--b, green); +} + +#twocycleinfallback_b { + --c: var(--d, red); + --d: var(--e, var(--c)); + --e: yellow; + background-color: orange; + background-color: var(--d, green); +} + +#twocycleinfallback_rb { + --d: var(--c, red); + --c: var(--e, var(--d)); + --e: yellow; + background-color: orange; + background-color: var(--c, green); +} + +#twocycleinchain_a { + --e: var(--f) red; + --f: var(--not-defined) var(--e); + background-color: orange; + background-color: var(--f, green); +} + +#twocycleinchain_ra { + --f: var(--e) red; + --e: var(--not-defined) var(--f); + background-color: orange; + background-color: var(--e, green); +} + +#twocycleinchain_b { + --g: var(--h) red; + --h: var(--i) var(--g); + --i: ; + background-color: orange; + background-color: var(--h, green); +} + +#twocycleinchain_rb { + --h: var(--g) red; + --g: var(--i) var(--h); + --i: ; + background-color: orange; + background-color: var(--g, green); +} + +#secondarycycle_chain { + --j: var(--k, pink); + --k: var(--j) var(--l); + --l: var(--k, red); + background-color: orange; + background-color: var(--j, var(--l, green)); +} + +#secondarycycle_chain_r { + --k: var(--j, pink); + --j: var(--k) var(--l); + --l: var(--j, red); + background-color: orange; + background-color: var(--k, var(--l, green)); +} + +#secondarycycle_fallback { + --m: var(--n, pink); + --n: var(--m, var(--o)); + --o: var(--n, red); + background-color: orange; + background-color: var(--m, var(--o, green)); +} + +#secondarycycle_fallback_r { + --n: var(--m, pink); + --m: var(--n, var(--o)); + --o: var(--m, red); + background-color: orange; + background-color: var(--n, var(--o, green)); +} +</style> + +<div id=twocycleinfallback_a></div> +<div id=twocycleinfallback_ra></div> +<div id=twocycleinfallback_b></div> +<div id=twocycleinfallback_rb></div> +<div id=twocycleinchain_a></div> +<div id=twocycleinchain_ra></div> +<div id=twocycleinchain_b></div> +<div id=twocycleinchain_rb></div> +<div id=secondarycycle_chain></div> +<div id=secondarycycle_chain_r></div> +<div id=secondarycycle_fallback></div> +<div id=secondarycycle_fallback_r></div> + +<script> +test(function() { + assert_equals(getComputedStyle(twocycleinfallback_a).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(twocycleinfallback_ra).backgroundColor, 'rgb(0, 128, 0)'); +}, 'A cycle is still invalid if it uses fallbacks (fallback forced)'); + +test(function() { + assert_equals(getComputedStyle(twocycleinfallback_b).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(twocycleinfallback_rb).backgroundColor, 'rgb(0, 128, 0)'); +}, 'A cycle is still invalid if it uses fallbacks (fallback not taken)'); + +test(function() { + assert_equals(getComputedStyle(twocycleinchain_a).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(twocycleinchain_ra).backgroundColor, 'rgb(0, 128, 0)'); +}, 'A cycle is still invalid if it uses chains (A)'); + +test(function() { + assert_equals(getComputedStyle(twocycleinchain_b).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(twocycleinchain_rb).backgroundColor, 'rgb(0, 128, 0)'); +}, 'A cycle is still invalid if it uses chains (B)'); + +test(function() { + assert_equals(getComputedStyle(secondarycycle_chain).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(secondarycycle_chain_r).backgroundColor, 'rgb(0, 128, 0)'); +}, 'Secondary cycles need to be detected too (secondary cycle in chain)'); + +test(function() { + assert_equals(getComputedStyle(secondarycycle_fallback).backgroundColor, 'rgb(0, 128, 0)'); + assert_equals(getComputedStyle(secondarycycle_fallback_r).backgroundColor, 'rgb(0, 128, 0)'); +}, 'Secondary cycles need to be detected too (secondary cycle in fallback)'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-event-properties.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-event-properties.html index 06cb268..c463150 100644 --- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-event-properties.html +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-event-properties.html
@@ -67,7 +67,7 @@ shouldBeTrue("lastPointerEvent.cancelable"); } - shouldBeEqualToNumber("lastPointerEvent.pointerId", 0); + shouldBeEqualToNumber("lastPointerEvent.pointerId", 1); // TODO(crbug.com/557817): linux_chromium_rel_ng fails here, sets to empty string. // shouldBeEqualToString("lastPointerEvent.pointerType", "mouse"); shouldBeTrue("lastPointerEvent.isPrimary");
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-pointer-event-properties.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-pointer-event-properties.html index e542c3f..0b0f118 100644 --- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-pointer-event-properties.html +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-pointer-event-properties.html
@@ -20,8 +20,8 @@ function checkPointerEvent(event) { receivedPointerEvents.push(event); test(function() { - assert_between_inclusive(event.pointerId, 0, POINTER_PROPERTIES.length - 1); - var pp = POINTER_PROPERTIES[event.pointerId]; + assert_between_inclusive(event.pointerId, 1, POINTER_PROPERTIES.length); + var pp = POINTER_PROPERTIES[event.pointerId-1]; for ( var i in pp ) assert_equals(event[i], pp[i], "" + i); }, "Pointer event properties for pointer " + event.pointerId + " on " + event.type);
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/invalid-object-with-fallback.html b/third_party/WebKit/LayoutTests/fast/replaced/invalid-object-with-fallback.html index b7c3c5cc..ab1ab1c 100644 --- a/third_party/WebKit/LayoutTests/fast/replaced/invalid-object-with-fallback.html +++ b/third_party/WebKit/LayoutTests/fast/replaced/invalid-object-with-fallback.html
@@ -1,8 +1,10 @@ <html> <head> <script> - if (window.testRunner) + if (window.testRunner) { testRunner.dumpAsText(); + testRunner.waitUntilDone(); + } function debug(str) { document.getElementById('console').innerHTML += str + "<br>"; @@ -12,17 +14,15 @@ <body> <object> <p>This test verifies that an <embed> tag is rendered along with other fallback content when an <object> fails to load. On success, you should see this text, followed by 'PASS'.</p> - <embed name="plugin" type="application/x-webkit-test-netscape"> + <embed name="plugin" type="application/x-blink-test-plugin"> </object> <div id="console"></div> <script> - if (window.internals) - internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(); - var plugin = document.plugin; - if (plugin && plugin.getURL) - debug("PASS"); - else - debug("FAIL"); + document.querySelector("embed").addEventListener("message", function (message) { + debug("PASS"); + if (window.testRunner) + testRunner.notifyDone(); + }); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/bidi-embedding-pop-and-push-same.html b/third_party/WebKit/LayoutTests/fast/text/bidi-embedding-pop-and-push-same.html index ae521d1b..f4d81476 100644 --- a/third_party/WebKit/LayoutTests/fast/text/bidi-embedding-pop-and-push-same.html +++ b/third_party/WebKit/LayoutTests/fast/text/bidi-embedding-pop-and-push-same.html
@@ -1,6 +1,7 @@ <meta charset="utf-8"> <style> div.group { border: 1px lightblue solid; padding: 4px; margin: 8px; } + [dir] { unicode-bidi: embed; } </style> <p> In each box below, the words or letters should be in the same order on every line.
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/bidi-LDB-2-HTML.html b/third_party/WebKit/LayoutTests/fast/text/international/bidi-LDB-2-HTML.html index 97041db..82a8700 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/bidi-LDB-2-HTML.html +++ b/third_party/WebKit/LayoutTests/fast/text/international/bidi-LDB-2-HTML.html
@@ -29,6 +29,7 @@ div.box { border:1px green solid; display:inline-block; padding:3px; margin:3px; vertical-align:middle; } +span[dir] { unicode-bidi: embed; } </STYLE> </HEAD> <BODY>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/bidi-ignored-for-first-child-inline.html b/third_party/WebKit/LayoutTests/fast/text/international/bidi-ignored-for-first-child-inline.html index 10eb488..3e2d349 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/bidi-ignored-for-first-child-inline.html +++ b/third_party/WebKit/LayoutTests/fast/text/international/bidi-ignored-for-first-child-inline.html
@@ -3,6 +3,7 @@ <title>Bidi properties ignored for inline container whose first child is an inline container</title> <style type="text/css"> .rlo { direction: rtl; unicode-bidi: bidi-override; } +[dir] { unicode-bidi: embed; } </style> </head> <body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium new file mode 100644 index 0000000..b577efa --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium
@@ -0,0 +1,6 @@ +This directory contains a copy of a test suite created by W3C I18N WG. + +A pull request to web-platform-tests is being worked on: +https://github.com/w3c/web-platform-tests/pull/2357 + +This directory should be removed when the pull request is merged and imported.
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html new file mode 100644 index 0000000..b5882eb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html new file mode 100644 index 0000000..16a308a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number, opposite direction</title> +<link rel="author" title="Richard Ishida" href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel="match" href='reference/dir-isolation-001-ref.html'> +<meta name="assert" content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">א</span> 3</div> +<div dir="ltr"><span dir="rtl">a</span> 3</div> +<div dir="rtl"><span dir="ltr">א</span> 3</div> +<div dir="rtl"><span dir="ltr">a</span> 3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html new file mode 100644 index 0000000..b5882eb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html new file mode 100644 index 0000000..197f49a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number, auto</title> +<link rel="author" title="Richard Ishida" href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel="match" href='reference/dir-isolation-001-ref.html'> +<meta name="assert" content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">א</span> 3</div> +<div dir="ltr"><span dir="auto">a</span> 3</div> +<div dir="rtl"><span dir="auto">א</span> 3</div> +<div dir="rtl"><span dir="auto">a</span> 3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html new file mode 100644 index 0000000..b5882eb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html new file mode 100644 index 0000000..95ec6c73 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number, same direction</title> +<link rel="author" title="Richard Ishida" href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel="match" href='reference/dir-isolation-001-ref.html'> +<meta name="assert" content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">א</span> 3</div> +<div dir="ltr"><span dir="ltr">a</span> 3</div> +<div dir="rtl"><span dir="rtl">א</span> 3</div> +<div dir="rtl"><span dir="rtl">a</span> 3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html new file mode 100644 index 0000000..f28559b5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number with intervening neutrals, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭< a < > 3 >‬</div><div dir="rtl">‭< 3 < > א >‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> +<div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭< a < > 3 >‬</div><div dir="rtl">‭< 3 < > א >‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html new file mode 100644 index 0000000..7b7029a2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number with intervening neutrals, opposite direction</title> +<link rel="author" title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-002a-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">> א ></span> > 3 ></div> +<div dir="ltr"><span dir="rtl">> a ></span> > 3 ></div> +<div dir="rtl"><span dir="ltr">> א ></span> > 3 ></div> +<div dir="rtl"><span dir="ltr">> a ></span> > 3 ></div> +</div> +<div class="ref"> +<div dir="ltr">‭< א < > 3 >‬</div> +<div dir="ltr">‭< a < > 3 >‬</div> +<div dir="rtl">‭< 3 < > א >‬</div> +<div dir="rtl">‭< 3 < > a >‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html new file mode 100644 index 0000000..d4eda21 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number with intervening neutrals, auto</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> +<div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html new file mode 100644 index 0000000..d448de5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number with intervening neutrals, auto</title> +<link rel="author" title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-002b-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">> א ></span> > 3 ></div> +<div dir="ltr"><span dir="auto">> a ></span> > 3 ></div> +<div dir="rtl"><span dir="auto">> א ></span> > 3 ></div> +<div dir="rtl"><span dir="auto">> a ></span> > 3 ></div> +</div> +<div class="ref"> +<div dir="ltr">‭< א < > 3 >‬</div> +<div dir="ltr">‭> a > > 3 >‬</div> +<div dir="rtl">‭< 3 < < א <‬</div> +<div dir="rtl">‭< 3 < > a >‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html new file mode 100644 index 0000000..6c21d014 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following number with intervening neutrals, same direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭> א > > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < < a <‬</div></div> +<div class="ref"><div dir="ltr">‭> א > > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < < a <‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html new file mode 100644 index 0000000..e88fb1c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following number with intervening neutrals, same direction</title> +<link rel="author" title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-002c-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from a following number.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">> א ></span> > 3 ></div> +<div dir="ltr"><span dir="ltr">> a ></span> > 3 ></div> +<div dir="rtl"><span dir="rtl">> א ></span> > 3 ></div> +<div dir="rtl"><span dir="rtl">> a ></span> > 3 ></div> +</div> +<div class="ref"> +<div dir="ltr">‭> א > > 3 >‬</div> +<div dir="ltr">‭> a > > 3 >‬</div> +<div dir="rtl">‭< 3 < < א <‬</div> +<div dir="rtl">‭< 3 < < a <‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html new file mode 100644 index 0000000..4c29838e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html new file mode 100644 index 0000000..9cf65c81 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following number, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-003-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and is directionally isolated from a following number, even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">א</span>3</div> +<div dir="ltr"><span dir="rtl">a</span>3</div> +<div dir="rtl"><span dir="ltr">א</span>3</div> +<div dir="rtl"><span dir="ltr">a</span>3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א3‬</div> +<div dir="ltr">‭a3‬</div> +<div dir="rtl">‭3א‬</div> +<div dir="rtl">‭3a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html new file mode 100644 index 0000000..4c29838e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html new file mode 100644 index 0000000..2c6b553 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following number, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-003-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and is directionally isolated from a following number, even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">א</span>3</div> +<div dir="ltr"><span dir="auto">a</span>3</div> +<div dir="rtl"><span dir="auto">א</span>3</div> +<div dir="rtl"><span dir="auto">a</span>3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א3‬</div> +<div dir="ltr">‭a3‬</div> +<div dir="rtl">‭3א‬</div> +<div dir="rtl">‭3a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html new file mode 100644 index 0000000..4c29838e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following number, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +<div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html new file mode 100644 index 0000000..ac873512 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following number, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-003-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and is directionally isolated from a following number, even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">א</span>3</div> +<div dir="ltr"><span dir="ltr">a</span>3</div> +<div dir="rtl"><span dir="rtl">א</span>3</div> +<div dir="rtl"><span dir="rtl">a</span>3</div> +</div> +<div class="ref"> +<div dir="ltr">‭א3‬</div> +<div dir="ltr">‭a3‬</div> +<div dir="rtl">‭3א‬</div> +<div dir="rtl">‭3a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html new file mode 100644 index 0000000..cb83dde --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html new file mode 100644 index 0000000..27a674c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-004-ref.html'> +<meta name='assert' content='Numeric element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="rtl">3</span></div> +<div dir="ltr">a <span dir="rtl">3</span></div> +<div dir="rtl">א <span dir="ltr">3</span></div> +<div dir="rtl">a <span dir="ltr">3</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html new file mode 100644 index 0000000..cb83dde --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html new file mode 100644 index 0000000..6fe74393 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: numbers isolated from preceding text, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-004-ref.html'> +<meta name='assert' content='Numeric element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="auto">3</span></div> +<div dir="ltr">a <span dir="auto">3</span></div> +<div dir="rtl">א <span dir="auto">3</span></div> +<div dir="rtl">a <span dir="auto">3</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html new file mode 100644 index 0000000..cb83dde --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html new file mode 100644 index 0000000..43d994b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: numbers isolated from preceding text, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-004-ref.html'> +<meta name='assert' content='Numeric element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="ltr">3</span></div> +<div dir="ltr">a <span dir="ltr">3</span></div> +<div dir="rtl">א <span dir="rtl">3</span></div> +<div dir="rtl">a <span dir="rtl">3</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א 3‬</div> +<div dir="ltr">‭a 3‬</div> +<div dir="rtl">‭3 א‬</div> +<div dir="rtl">‭3 a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html new file mode 100644 index 0000000..4a6c301a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html new file mode 100644 index 0000000..2fbddbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-005-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">א</span> ב...</div> +<div dir="ltr"><span dir="rtl">a</span> b...</div> +<div dir="rtl"><span dir="ltr">a</span> b...</div> +<div dir="rtl"><span dir="ltr">א</span> ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב...‬</div> +<div dir="ltr">‭a b...‬</div> +<div dir="rtl">‭...b a‬</div> +<div dir="rtl">‭...ב א‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html new file mode 100644 index 0000000..4a6c301a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html new file mode 100644 index 0000000..d61e258f2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-005-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">א</span> ב...</div> +<div dir="ltr"><span dir="auto">a</span> b...</div> +<div dir="rtl"><span dir="auto">a</span> b...</div> +<div dir="rtl"><span dir="auto">א</span> ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב...‬</div> +<div dir="ltr">‭a b...‬</div> +<div dir="rtl">‭...b a‬</div> +<div dir="rtl">‭...ב א‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html new file mode 100644 index 0000000..4a6c301a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html new file mode 100644 index 0000000..d544275 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-005-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">א</span> ב...</div> +<div dir="ltr"><span dir="ltr">a</span> b...</div> +<div dir="rtl"><span dir="rtl">a</span> b...</div> +<div dir="rtl"><span dir="rtl">א</span> ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב...‬</div> +<div dir="ltr">‭a b...‬</div> +<div dir="rtl">‭...b a‬</div> +<div dir="rtl">‭...ב א‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html new file mode 100644 index 0000000..0f6b7bbb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text with intervening neutrals, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> +<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html new file mode 100644 index 0000000..430df00d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text with intervening neutrals, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-006-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text despite intervening neutrals.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">> א ></span> > ב >...</div> +<div dir="rtl"><span dir="ltr">> a ></span> > b >...</div> +</div> +<div class="ref"> +<div dir="ltr">‭< א < > ב >...‬</div> +<div dir="rtl">‭...< b < > a >‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html new file mode 100644 index 0000000..0f6b7bbb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text with intervening neutrals, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> +<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html new file mode 100644 index 0000000..a6da487 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text with intervening neutrals, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-006-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text despite intervening neutrals.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">> א ></span> > ב >...</div> +<div dir="rtl"><span dir="auto">> a ></span> > b >...</div> +</div> +<div class="ref"> +<div dir="ltr">‭< א < > ב >...‬</div> +<div dir="rtl">‭...< b < > a >‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html new file mode 100644 index 0000000..0347c09 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from following text with intervening neutrals, same direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭> א > > ב >...‬</div><div dir="rtl">‭...< b < < a <‬</div></div> +<div class="ref"><div dir="ltr">‭> א > > ב >...‬</div><div dir="rtl">‭...< b < < a <‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html new file mode 100644 index 0000000..3407d37 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from following text with intervening neutrals, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-006c-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text despite intervening neutrals.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">> א ></span> > ב >...</div> +<div dir="rtl"><span dir="rtl">> a ></span> > b >...</div> +</div> +<div class="ref"> +<div dir="ltr">‭> א > > ב >...‬</div> +<div dir="rtl">‭...< b < < a <‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html new file mode 100644 index 0000000..665153d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html new file mode 100644 index 0000000..e8b37b1b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following text, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-007-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="rtl">א</span>ב...</div> +<div dir="ltr"><span dir="rtl">a</span>b...</div> +<div dir="rtl"><span dir="ltr">a</span>b...</div> +<div dir="rtl"><span dir="ltr">א</span>ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭אב...‬</div> +<div dir="ltr">‭ab...‬</div> +<div dir="rtl">‭...ba‬</div> +<div dir="rtl">‭...בא‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html new file mode 100644 index 0000000..665153d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html new file mode 100644 index 0000000..c54e63d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following text, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-007-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="auto">א</span>ב...</div> +<div dir="ltr"><span dir="auto">a</span>b...</div> +<div dir="rtl"><span dir="auto">a</span>b...</div> +<div dir="rtl"><span dir="auto">א</span>ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭אב...‬</div> +<div dir="ltr">‭ab...‬</div> +<div dir="rtl">‭...ba‬</div> +<div dir="rtl">‭...בא‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html new file mode 100644 index 0000000..665153d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from immediately following text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html new file mode 100644 index 0000000..b9c5219 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from immediately following text, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-007-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from following text even with no intervening white space.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr"><span dir="ltr">א</span>ב...</div> +<div dir="ltr"><span dir="ltr">a</span>b...</div> +<div dir="rtl"><span dir="rtl">a</span>b...</div> +<div dir="rtl"><span dir="rtl">א</span>ב...</div> +</div> +<div class="ref"> +<div dir="ltr">‭אב...‬</div> +<div dir="ltr">‭ab...‬</div> +<div dir="rtl">‭...ba‬</div> +<div dir="rtl">‭...בא‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html new file mode 100644 index 0000000..8eb90f8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html new file mode 100644 index 0000000..1455fd5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from preceding text, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-008-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="rtl">ב</span></div> +<div dir="ltr">a <span dir="rtl">b</span></div> +<div dir="rtl">א <span dir="ltr">ב</span></div> +<div dir="rtl">a <span dir="ltr">b</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב‬</div> +<div dir="ltr">‭a b‬</div> +<div dir="rtl">‭ב א‬</div> +<div dir="rtl">‭b a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html new file mode 100644 index 0000000..8eb90f8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html new file mode 100644 index 0000000..f12e6d6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from preceding text, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-008-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="auto">ב</span></div> +<div dir="ltr">a <span dir="auto">b</span></div> +<div dir="rtl">א <span dir="auto">ב</span></div> +<div dir="rtl">a <span dir="auto">b</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב‬</div> +<div dir="ltr">‭a b‬</div> +<div dir="rtl">‭ב א‬</div> +<div dir="rtl">‭b a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html new file mode 100644 index 0000000..8eb90f8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from preceding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html new file mode 100644 index 0000000..b1754cf --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>The dir attribute: isolated from preceding text, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-008-ref.html'> +<meta name='assert' content='Element content with a dir attribute is treated as a neutral character and directionally isolated from preceding text.'> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!--Notes: +Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. +--> +<div class="test"> +<div dir="ltr">א <span dir="ltr">ב</span></div> +<div dir="ltr">a <span dir="ltr">b</span></div> +<div dir="rtl">א <span dir="rtl">ב</span></div> +<div dir="rtl">a <span dir="rtl">b</span></div> +</div> +<div class="ref"> +<div dir="ltr">‭א ב‬</div> +<div dir="ltr">‭a b‬</div> +<div dir="rtl">‭ב א‬</div> +<div dir="rtl">‭b a‬</div> +</div> +</body></html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html new file mode 100644 index 0000000..1d2f57c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, opposite direction</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭ג < < b < < א...‬</div><div dir="rtl">‭...a > > ב > > c‬</div></div> +<div class="ref"><div dir="ltr">‭ג < < b < < א...‬</div><div dir="rtl">‭...a > > ב > > c‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html new file mode 100644 index 0000000..63a9706 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html lang="en" > +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, opposite direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-009-ref.html'> +<meta name='assert' content="Element content with a dir attribute is treated as a neutral character and directionally isolated from surrounding text."> +<style type='text/css'> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב +from forming a single RTL run and thus keep the >s between from being mirrored into <s. +--> +<div class="test"> +<div dir="ltr">א > <span dir="rtl">> b ></span> > ג...</div> +<div dir="rtl">a > <span dir="ltr">> ב ></span> > c...</div> +</div> +<div class="ref"> +<div dir="ltr">‭ג < < b < < א...‬</div> +<div dir="rtl">‭...a > > ב > > c‬</div> +</div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html new file mode 100644 index 0000000..30ee14c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, auto</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> +<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html new file mode 100644 index 0000000..57098fa --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html lang="en" > +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, auto</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-009b-ref.html'> +<meta name='assert' content="Element content with a dir attribute is treated as a neutral character and directionally isolated from surrounding text."> +<style type='text/css'> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב +from forming a single RTL run and thus keep the >s between from being mirrored into <s. +--> +<div class="test"> +<div dir="ltr">א > <span dir="auto">> b ></span> > ג...</div> +<div dir="rtl">a > <span dir="auto">> ב ></span> > c...</div> +</div> +<div class="ref"> +<div dir="ltr">‭ג < > b > < א...‬</div> +<div dir="rtl">‭...a > < ב < > c‬</div> +</div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html new file mode 100644 index 0000000..30ee14c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, auto</title> +<style type="text/css"> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> +<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html new file mode 100644 index 0000000..4aac3184 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html lang="en" > +<head> +<meta charset="utf-8"/> +<title>The dir attribute: isolated from surrounding text, same direction</title> +<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> +<link rel="help" href='http://www.w3.org/TR/html5/dom.html#requirements-relating-to-the-bidirectional-algorithm'> +<link rel='match' href='reference/dir-isolation-009b-ref.html'> +<meta name='assert' content="Element content with a dir attribute is treated as a neutral character and directionally isolated from surrounding text."> +<style type='text/css'> +.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } +input { margin: 5px; } +</style> +</head> +<body> +<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: +א ... ו - The first six Hebrew letters (strongly RTL). +‭ - The LRO (left-to-right-override) formatting character. +‬ - The PDF (pop directional formatting) formatting character; closes LRO. +If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב +from forming a single RTL run and thus keep the >s between from being mirrored into <s. +--> +<div class="test"> +<div dir="ltr">א > <span dir="ltr">> b ></span> > ג...</div> +<div dir="rtl">a > <span dir="rtl">> ב ></span> > c...</div> +</div> +<div class="ref"> +<div dir="ltr">‭ג < > b > < א...‬</div> +<div dir="rtl">‭...a > < ב < > c‬</div> +</div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html index f92779b3..ace8802a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html
@@ -287,7 +287,7 @@ var xhr = new XMLHttpRequest(); xhr.open("GET", scriptName, false); xhr.send(null); - window.eval(xhr.responseText + "\n//@ sourceURL=" + scriptName); + window.eval(xhr.responseText + "\n//# sourceURL=" + scriptName); } InspectorTest.safeWrap = function(func, onexception)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js index 397c7cc..5cca2aa8 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -507,7 +507,7 @@ var lineCount = source.lineEndings().length; var endLine = startLine + lineCount - 1; var endColumn = lineCount === 1 ? startColumn + source.length : source.length - source.lineEndings()[lineCount - 2]; - var hasSourceURL = !!source.match(/\/\/#\ssourceURL=\s*(\S*?)\s*$/m) || !!source.match(/\/\/@\ssourceURL=\s*(\S*?)\s*$/m); + var hasSourceURL = !!source.match(/\/\/#\ssourceURL=\s*(\S*?)\s*$/m); var script = new WebInspector.Script(debuggerModel, scriptId, url, startLine, startColumn, endLine, endColumn, isContentScript, null, hasSourceURL); script.requestContent = function(callback) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js index a0dbaf1c..02d4a8ac 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
@@ -297,7 +297,7 @@ { var regex = text ? new RegExp(text, "i") : null; InspectorTest.addResult("Filtering styles by: " + text); - WebInspector.panels.elements.sidebarPanes.styles._onFilterChanged(regex); + WebInspector.panels.elements.sidebarPanes.styles.onFilterChanged(regex); } InspectorTest.dumpRenderedMatchedStyles = function()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/resources/selector-line-deprecated.css b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/resources/selector-line-deprecated.css index 3115b25..b1c3454 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/resources/selector-line-deprecated.css +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/resources/selector-line-deprecated.css
@@ -3,4 +3,4 @@ #container #inspected { color: green; } -/*@ sourceMappingURL=selector-line.css.map */ \ No newline at end of file +/*# sourceMappingURL=selector-line.css.map */
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-objects-tracking.html b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-objects-tracking.html index 0bfe268..d54911c 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-objects-tracking.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-objects-tracking.html
@@ -76,7 +76,7 @@ } InspectorTest.sendCommand("HeapProfiler.startTrackingHeapObjects", {}, trackingStarted); - //@ sourceURL=heap-objects-tracking.html + //# sourceURL=heap-objects-tracking.html } </script> </head>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-samples-in-snapshot.html b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-samples-in-snapshot.html index 902327f..9b597207 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-samples-in-snapshot.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/heap-profiler/heap-samples-in-snapshot.html
@@ -85,7 +85,7 @@ } InspectorTest.sendCommand("HeapProfiler.startTrackingHeapObjects", {}, trackingStarted); - //@ sourceURL=heap-objects-tracking.html + //# sourceURL=heap-objects-tracking.html } </script> </head>
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt index b4db6c1..f566ceb 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt
@@ -5,43 +5,43 @@ "M", 88, 8, - "L", - 88, + "Q", + 121, 8, - "C", - 132, + 145, + 31, + "Q", + 168, + 55, + 168, + 88, + "Q", + 168, + 121, + 145, + 145, + "Q", + 121, + 168, + 88, + 168, + "Q", + 55, + 168, + 31, + 145, + "Q", 8, - 168, - 44, - 168, - 88, - "L", - 168, - 88, - "C", - 168, - 132, - 132, - 168, - 88, - 168, - "L", - 88, - 168, - "C", - 44, - 168, - 8, - 132, + 121, 8, 88, - "L", + "Q", 8, - 88, - "C", - 8, - 44, - 44, + 55, + 31, + 31, + "Q", + 55, 8, 88, 8, @@ -54,43 +54,43 @@ "M", 88, -24, - "L", - 88, + "Q", + 134, -24, - "C", - 150, + 167, + 9, + "Q", + 200, + 42, + 200, + 88, + "Q", + 200, + 134, + 167, + 167, + "Q", + 134, + 200, + 88, + 200, + "Q", + 42, + 200, + 9, + 167, + "Q", -24, - 200, - 26, - 200, - 88, - "L", - 200, - 88, - "C", - 200, - 150, - 150, - 200, - 88, - 200, - "L", - 88, - 200, - "C", - 26, - 200, - -24, - 150, + 134, -24, 88, - "L", + "Q", -24, - 88, - "C", - -24, - 26, - 26, + 42, + 9, + 9, + "Q", + 42, -24, 88, -24, @@ -194,43 +194,43 @@ "M", 248, 56, - "L", - 248, + "Q", + 261, 56, - "C", - 266, - 56, + 271, + 65, + "Q", 280, - 70, + 75, 280, 88, - "L", + "Q", 280, - 88, - "C", - 280, - 106, - 266, + 101, + 271, + 111, + "Q", + 261, 120, 248, 120, - "L", - 248, + "Q", + 235, 120, - "C", - 230, - 120, + 225, + 111, + "Q", 216, - 106, + 101, 216, 88, - "L", + "Q", 216, - 88, - "C", - 216, - 70, - 230, + 75, + 225, + 65, + "Q", + 235, 56, 248, 56, @@ -243,43 +243,43 @@ "M", 248, 24, - "L", - 248, + "Q", + 275, 24, - "C", - 283, - 24, + 293, + 43, + "Q", 312, - 53, + 61, 312, 88, - "L", + "Q", 312, - 88, - "C", - 312, - 123, - 283, + 115, + 293, + 133, + "Q", + 275, 152, 248, 152, - "L", - 248, + "Q", + 221, 152, - "C", - 213, - 152, + 203, + 133, + "Q", 184, - 123, + 115, 184, 88, - "L", + "Q", 184, - 88, - "C", - 184, - 53, - 213, + 61, + 203, + 43, + "Q", + 221, 24, 248, 24, @@ -386,40 +386,52 @@ "L", 408, 24, - "C", - 443, + "Q", + 435, 24, + 453, + 43, + "Q", 472, - 53, + 61, 472, 88, "L", 472, 136, - "C", + "Q", 472, - 145, - 465, + 143, + 467, + 147, + "Q", + 463, 152, 456, 152, "L", 408, 152, - "C", - 373, + "Q", + 381, 152, + 363, + 133, + "Q", 344, - 123, + 115, 344, 88, "L", 344, 40, - "C", + "Q", 344, - 31, - 351, + 33, + 349, + 29, + "Q", + 353, 24, 360, 24, @@ -435,40 +447,52 @@ "L", 408, -8, - "C", - 461, + "Q", + 448, -8, + 476, + 20, + "Q", 504, - 35, + 48, 504, 88, "L", 504, 136, - "C", + "Q", 504, - 163, - 483, + 156, + 490, + 170, + "Q", + 476, 184, 456, 184, "L", 408, 184, - "C", - 355, + "Q", + 368, 184, + 340, + 156, + "Q", 312, - 141, + 128, 312, 88, "L", 312, 40, - "C", + "Q", 312, - 13, - 333, + 20, + 326, + 6, + "Q", + 340, -8, 360, -8, @@ -572,43 +596,43 @@ "M", 568, 8, - "L", - 568, + "Q", + 601, 8, - "C", - 612, - 8, + 625, + 24, + "Q", 648, - 33, + 41, 648, 64, - "L", + "Q", 648, - 64, - "C", - 648, - 95, - 612, + 87, + 625, + 104, + "Q", + 601, 120, 568, 120, - "L", - 568, + "Q", + 535, 120, - "C", - 524, - 120, + 511, + 104, + "Q", 488, - 95, + 87, 488, 64, - "L", + "Q", 488, - 64, - "C", - 488, - 33, - 524, + 41, + 511, + 24, + "Q", + 535, 8, 568, 8, @@ -621,43 +645,43 @@ "M", 568, -24, - "L", - 568, + "Q", + 614, -24, - "C", - 630, - -24, + 647, + 2, + "Q", 680, - 15, + 28, 680, 64, - "L", + "Q", 680, - 64, - "C", - 680, - 113, - 630, + 100, + 647, + 126, + "Q", + 614, 152, 568, 152, - "L", - 568, + "Q", + 522, 152, - "C", - 506, - 152, + 489, + 126, + "Q", 456, - 113, + 100, 456, 64, - "L", + "Q", 456, - 64, - "C", - 456, - 15, - 506, + 28, + 489, + 2, + "Q", + 522, -24, 568, -24, @@ -764,40 +788,52 @@ "L", 600, 168, - "C", - 635, + "Q", + 627, 168, + 645, + 187, + "Q", 664, - 197, + 205, 664, 232, "L", 664, 264, - "C", + "Q", 664, - 282, - 650, + 277, + 655, + 287, + "Q", + 645, 296, 632, 296, "L", 568, 296, - "C", - 550, + "Q", + 555, 296, + 545, + 287, + "Q", 536, - 282, + 277, 536, 264, "L", 536, 200, - "C", + "Q", 536, - 182, - 550, + 187, + 545, + 177, + "Q", + 555, 168, 568, 168, @@ -813,40 +849,52 @@ "L", 600, 136, - "C", - 653, + "Q", + 640, 136, + 668, + 164, + "Q", 696, - 179, + 192, 696, 232, "L", 696, 264, - "C", + "Q", 696, - 299, - 667, + 291, + 677, + 309, + "Q", + 659, 328, 632, 328, "L", 568, 328, - "C", - 533, + "Q", + 541, 328, + 523, + 309, + "Q", 504, - 299, + 291, 504, 264, "L", 504, 200, - "C", + "Q", 504, - 165, - 533, + 173, + 523, + 155, + "Q", + 541, 136, 568, 136,
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt index a189e8c3..8e84186 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt
@@ -5,43 +5,43 @@ "M", 88, 8, - "L", - 88, + "Q", + 121, 8, - "C", - 132, + 145, + 31, + "Q", + 168, + 55, + 168, + 88, + "Q", + 168, + 121, + 145, + 145, + "Q", + 121, + 168, + 88, + 168, + "Q", + 55, + 168, + 31, + 145, + "Q", 8, - 168, - 44, - 168, - 88, - "L", - 168, - 88, - "C", - 168, - 132, - 132, - 168, - 88, - 168, - "L", - 88, - 168, - "C", - 44, - 168, - 8, - 132, + 121, 8, 88, - "L", + "Q", 8, - 88, - "C", - 8, - 44, - 44, + 55, + 31, + 31, + "Q", + 55, 8, 88, 8, @@ -54,43 +54,43 @@ "M", 88, -24, - "L", - 88, + "Q", + 134, -24, - "C", - 150, + 167, + 9, + "Q", + 200, + 42, + 200, + 88, + "Q", + 200, + 134, + 167, + 167, + "Q", + 134, + 200, + 88, + 200, + "Q", + 42, + 200, + 9, + 167, + "Q", -24, - 200, - 26, - 200, - 88, - "L", - 200, - 88, - "C", - 200, - 150, - 150, - 200, - 88, - 200, - "L", - 88, - 200, - "C", - 26, - 200, - -24, - 150, + 134, -24, 88, - "L", + "Q", -24, - 88, - "C", - -24, - 26, - 26, + 42, + 9, + 9, + "Q", + 42, -24, 88, -24, @@ -194,43 +194,43 @@ "M", 88, 8, - "L", - 88, + "Q", + 121, 8, - "C", - 132, + 145, + 31, + "Q", + 168, + 55, + 168, + 88, + "Q", + 168, + 121, + 145, + 145, + "Q", + 121, + 168, + 88, + 168, + "Q", + 55, + 168, + 31, + 145, + "Q", 8, - 168, - 44, - 168, - 88, - "L", - 168, - 88, - "C", - 168, - 132, - 132, - 168, - 88, - 168, - "L", - 88, - 168, - "C", - 44, - 168, - 8, - 132, + 121, 8, 88, - "L", + "Q", 8, - 88, - "C", - 8, - 44, - 44, + 55, + 31, + 31, + "Q", + 55, 8, 88, 8, @@ -243,43 +243,43 @@ "M", 88, -24, - "L", - 88, + "Q", + 134, -24, - "C", - 150, + 167, + 9, + "Q", + 200, + 42, + 200, + 88, + "Q", + 200, + 134, + 167, + 167, + "Q", + 134, + 200, + 88, + 200, + "Q", + 42, + 200, + 9, + 167, + "Q", -24, - 200, - 26, - 200, - 88, - "L", - 200, - 88, - "C", - 200, - 150, - 150, - 200, - 88, - 200, - "L", - 88, - 200, - "C", - 26, - 200, - -24, - 150, + 134, -24, 88, - "L", + "Q", -24, - 88, - "C", - -24, - 26, - 26, + 42, + 9, + 9, + "Q", + 42, -24, 88, -24,
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt index 1292e77..1d9df9f 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment-expected.txt
@@ -6,9 +6,6 @@ Running: testSourceURLComment body { color: black; } -Running: testDeprecatedSourceURLComment -body { color: black; } - Running: testNonRelativeURL body { color: red; }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html index 8ab1c2c..c27ce9ec1 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/stylesheet-source-url-comment.html
@@ -17,13 +17,6 @@ document.head.appendChild(styleElement); } -function addInlineStyleSheetDeprecated() -{ - var styleElement = document.createElement("style"); - styleElement.textContent = "body { color: black; }\n/*@ sourceURL=css/addedInlineStylesheetDeprecated.css */"; - document.head.appendChild(styleElement); -} - function addInlineStyleSheetNonRelative() { var styleElement = document.createElement("style"); @@ -77,19 +70,6 @@ } }, - function testDeprecatedSourceURLComment(next) - { - InspectorTest.showScriptSource("css/addedInlineStylesheetDeprecated.css", didShowSource); - InspectorTest.evaluateInPage("setTimeout(addInlineStyleSheetDeprecated, 0)"); - - function didShowSource(sourceFrame) - { - InspectorTest.addResult(sourceFrame.textEditor.text()); - forEachHeaderMatchingURL("addedInlineStylesheetDeprecated", checkHeaderHasSourceURL); - next(); - } - }, - function testNonRelativeURL(next) { InspectorTest.showScriptSource("/css/nonRelativeInlineStylesheet.css", didShowSource);
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-details-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-details-expected.txt index 3e8536e..5e8a6154 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-details-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-details-expected.txt
@@ -4,10 +4,12 @@ URL: timeline-network-resource.js Duration: string Request Method: GET +Priority: Low Mime Type: string URL: anImage.png Duration: string Request Method: GET +Priority: Lowest Mime Type: string Preview:
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt index e71cfc05..e7c5944 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt
@@ -6,6 +6,7 @@ { data : { frame : <string> + priority : "Low" requestId : <string> requestMethod : "GET" stackTrace : <object>
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png new file mode 100644 index 0000000..0da4ae8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png new file mode 100644 index 0000000..123207e --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png new file mode 100644 index 0000000..96afef2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/css3/masking/clip-path-inset-corners-expected.png b/third_party/WebKit/LayoutTests/platform/android/css3/masking/clip-path-inset-corners-expected.png new file mode 100644 index 0000000..ad3006f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/css3/masking/clip-path-inset-corners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/svg-as-mask-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/svg-as-mask-expected.png new file mode 100644 index 0000000..5a20b5b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/backgrounds/svg-as-mask-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusAllStylesAllCorners-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusAllStylesAllCorners-expected.png new file mode 100644 index 0000000..0310b31 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusAllStylesAllCorners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed01-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed01-expected.png new file mode 100644 index 0000000..800b25d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed01-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed02-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed02-expected.png new file mode 100644 index 0000000..d6dbe01e --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed02-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed03-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed03-expected.png new file mode 100644 index 0000000..f34d901 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed03-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed04-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed04-expected.png new file mode 100644 index 0000000..6171f61 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed04-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed05-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed05-expected.png new file mode 100644 index 0000000..c8e9524 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed05-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed06-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed06-expected.png new file mode 100644 index 0000000..2454409 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDashed06-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted01-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted01-expected.png new file mode 100644 index 0000000..771f8a6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted01-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted02-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted02-expected.png new file mode 100644 index 0000000..bf08730 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted02-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted03-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted03-expected.png new file mode 100644 index 0000000..68e6fb3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted03-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted04-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted04-expected.png new file mode 100644 index 0000000..1174d032 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted04-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted06-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted06-expected.png new file mode 100644 index 0000000..651a4b36 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/borderRadiusDotted06-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-expected.png new file mode 100644 index 0000000..b2025cb --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-subpixel-expected.png new file mode 100644 index 0000000..9498fea --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/box-shadow/inset-subpixel-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/masking/clip-path-inset-large-radii-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/masking/clip-path-inset-large-radii-expected.png new file mode 100644 index 0000000..1463895 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/masking/clip-path-inset-large-radii-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png new file mode 100644 index 0000000..eb142f5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png new file mode 100644 index 0000000..0fb227d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt b/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt new file mode 100644 index 0000000..b4db6c1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-expected.txt
@@ -0,0 +1,1491 @@ +circle{ + "paths": [ + { + "path": [ + "M", + 88, + 8, + "L", + 88, + 8, + "C", + 132, + 8, + 168, + 44, + 168, + 88, + "L", + 168, + 88, + "C", + 168, + 132, + 132, + 168, + 88, + 168, + "L", + 88, + 168, + "C", + 44, + 168, + 8, + 132, + 8, + 88, + "L", + 8, + 88, + "C", + 8, + 44, + 44, + 8, + 88, + 8, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 88, + -24, + "L", + 88, + -24, + "C", + 150, + -24, + 200, + 26, + 200, + 88, + "L", + 200, + 88, + "C", + 200, + 150, + 150, + 200, + 88, + 200, + "L", + 88, + 200, + "C", + 26, + 200, + -24, + 150, + -24, + 88, + "L", + -24, + 88, + "C", + -24, + 26, + 26, + -24, + 88, + -24, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 168, + 8, + "L", + 168, + 168, + "L", + 8, + 168, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "circle", + "className": ".float.circle", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +insetSimpleRound{ + "paths": [ + { + "path": [ + "M", + 248, + 56, + "L", + 248, + 56, + "C", + 266, + 56, + 280, + 70, + 280, + 88, + "L", + 280, + 88, + "C", + 280, + 106, + 266, + 120, + 248, + 120, + "L", + 248, + 120, + "C", + 230, + 120, + 216, + 106, + 216, + 88, + "L", + 216, + 88, + "C", + 216, + 70, + 230, + 56, + 248, + 56, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 248, + 24, + "L", + 248, + 24, + "C", + 283, + 24, + 312, + 53, + 312, + 88, + "L", + 312, + 88, + "C", + 312, + 123, + 283, + 152, + 248, + 152, + "L", + 248, + 152, + "C", + 213, + 152, + 184, + 123, + 184, + 88, + "L", + 184, + 88, + "C", + 184, + 53, + 213, + 24, + 248, + 24, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 184, + 24, + "L", + 312, + 24, + "L", + 312, + 152, + "L", + 184, + 152, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 184, + 24, + "L", + 312, + 24, + "L", + 312, + 152, + "L", + 184, + 152, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 184, + 24, + "L", + 312, + 24, + "L", + 312, + 152, + "L", + 184, + 152, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 168, + 8, + "L", + 328, + 8, + "L", + 328, + 168, + "L", + 168, + 168, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "insetSimpleRound", + "className": ".float.insetSimpleRound", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +insetComplexRound{ + "paths": [ + { + "path": [ + "M", + 360, + 24, + "L", + 408, + 24, + "C", + 443, + 24, + 472, + 53, + 472, + 88, + "L", + 472, + 136, + "C", + 472, + 145, + 465, + 152, + 456, + 152, + "L", + 408, + 152, + "C", + 373, + 152, + 344, + 123, + 344, + 88, + "L", + 344, + 40, + "C", + 344, + 31, + 351, + 24, + 360, + 24, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 360, + -8, + "L", + 408, + -8, + "C", + 461, + -8, + 504, + 35, + 504, + 88, + "L", + 504, + 136, + "C", + 504, + 163, + 483, + 184, + 456, + 184, + "L", + 408, + 184, + "C", + 355, + 184, + 312, + 141, + 312, + 88, + "L", + 312, + 40, + "C", + 312, + 13, + 333, + -8, + 360, + -8, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 344, + 24, + "L", + 472, + 24, + "L", + 472, + 152, + "L", + 344, + 152, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 344, + 24, + "L", + 472, + 24, + "L", + 472, + 152, + "L", + 344, + 152, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 344, + 24, + "L", + 472, + 24, + "L", + 472, + 152, + "L", + 344, + 152, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 328, + 8, + "L", + 488, + 8, + "L", + 488, + 168, + "L", + 328, + 168, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "insetComplexRound", + "className": ".float.insetComplexRound", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +ellipse{ + "paths": [ + { + "path": [ + "M", + 568, + 8, + "L", + 568, + 8, + "C", + 612, + 8, + 648, + 33, + 648, + 64, + "L", + 648, + 64, + "C", + 648, + 95, + 612, + 120, + 568, + 120, + "L", + 568, + 120, + "C", + 524, + 120, + 488, + 95, + 488, + 64, + "L", + 488, + 64, + "C", + 488, + 33, + 524, + 8, + 568, + 8, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 568, + -24, + "L", + 568, + -24, + "C", + 630, + -24, + 680, + 15, + 680, + 64, + "L", + 680, + 64, + "C", + 680, + 113, + 630, + 152, + 568, + 152, + "L", + 568, + 152, + "C", + 506, + 152, + 456, + 113, + 456, + 64, + "L", + 456, + 64, + "C", + 456, + 15, + 506, + -24, + 568, + -24, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 504, + 24, + "L", + 632, + 24, + "L", + 632, + 104, + "L", + 504, + 104, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 504, + 24, + "L", + 632, + 24, + "L", + 632, + 104, + "L", + 504, + 104, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 504, + 24, + "L", + 632, + 24, + "L", + 632, + 104, + "L", + 504, + 104, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 488, + 8, + "L", + 648, + 8, + "L", + 648, + 120, + "L", + 488, + 120, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "ellipse", + "className": ".float.ellipse", + "nodeWidth": "128", + "nodeHeight": "80" + }, + "displayAsMaterial": false +} +contentBox{ + "paths": [ + { + "path": [ + "M", + 568, + 168, + "L", + 600, + 168, + "C", + 635, + 168, + 664, + 197, + 664, + 232, + "L", + 664, + 264, + "C", + 664, + 282, + 650, + 296, + 632, + 296, + "L", + 568, + 296, + "C", + 550, + 296, + 536, + 282, + 536, + 264, + "L", + 536, + 200, + "C", + 536, + 182, + 550, + 168, + 568, + 168, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 568, + 136, + "L", + 600, + 136, + "C", + 653, + 136, + 696, + 179, + 696, + 232, + "L", + 696, + 264, + "C", + 696, + 299, + 667, + 328, + 632, + 328, + "L", + 568, + 328, + "C", + 533, + 328, + 504, + 299, + 504, + 264, + "L", + 504, + 200, + "C", + 504, + 165, + 533, + 136, + 568, + 136, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 536, + 168, + "L", + 664, + 168, + "L", + 664, + 296, + "L", + 536, + 296, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 504, + 152, + "L", + 680, + 152, + "L", + 680, + 312, + "L", + 504, + 312, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 504, + 152, + "L", + 680, + 152, + "L", + 680, + 312, + "L", + 504, + 312, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 488, + 120, + "L", + 696, + 120, + "L", + 696, + 328, + "L", + 488, + 328, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "contentBox", + "className": ".float.contentBox", + "nodeWidth": "176", + "nodeHeight": "160" + }, + "displayAsMaterial": false +} +polygon{ + "paths": [ + { + "path": [ + "M", + 8, + 328, + "L", + 8, + 528, + "L", + 208, + 328, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 24, + 344, + "L", + 152, + 344, + "L", + 152, + 472, + "L", + 24, + 472, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 24, + 344, + "L", + 152, + 344, + "L", + 152, + 472, + "L", + 24, + 472, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 24, + 344, + "L", + 152, + 344, + "L", + 152, + 472, + "L", + 24, + 472, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 328, + "L", + 168, + 328, + "L", + 168, + 488, + "L", + 8, + 488, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "polygon", + "className": ".float.polygon", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +raster{ + "paths": [ + { + "path": [ + "M", + 184, + 344, + "L", + 284, + 344, + "L", + 284, + 444, + "L", + 184, + 444, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 157, + 328, + "L", + 311, + 328, + "L", + 311, + 329, + "L", + 157, + 329, + "Z", + "M", + 156, + 329, + "L", + 312, + 329, + "L", + 312, + 331, + "L", + 156, + 331, + "Z", + "M", + 155, + 331, + "L", + 313, + 331, + "L", + 313, + 333, + "L", + 155, + 333, + "Z", + "M", + 154, + 333, + "L", + 314, + 333, + "L", + 314, + 337, + "L", + 154, + 337, + "Z", + "M", + 153, + 337, + "L", + 315, + 337, + "L", + 315, + 344, + "L", + 153, + 344, + "Z", + "M", + 152, + 344, + "L", + 316, + 344, + "L", + 316, + 444, + "L", + 152, + 444, + "Z", + "M", + 153, + 444, + "L", + 315, + 444, + "L", + 315, + 451, + "L", + 153, + 451, + "Z", + "M", + 154, + 451, + "L", + 314, + 451, + "L", + 314, + 455, + "L", + 154, + 455, + "Z", + "M", + 155, + 455, + "L", + 313, + 455, + "L", + 313, + 457, + "L", + 155, + 457, + "Z", + "M", + 156, + 457, + "L", + 312, + 457, + "L", + 312, + 459, + "L", + 156, + 459, + "Z", + "M", + 157, + 459, + "L", + 311, + 459, + "L", + 311, + 461, + "L", + 157, + 461, + "Z", + "M", + 158, + 461, + "L", + 310, + 461, + "L", + 310, + 462, + "L", + 158, + 462, + "Z", + "M", + 159, + 462, + "L", + 309, + 462, + "L", + 309, + 463, + "L", + 159, + 463, + "Z", + "M", + 160, + 463, + "L", + 308, + 463, + "L", + 308, + 465, + "L", + 160, + 465, + "Z", + "M", + 161, + 465, + "L", + 307, + 465, + "L", + 307, + 466, + "L", + 161, + 466, + "Z", + "M", + 162, + 466, + "L", + 306, + 466, + "L", + 306, + 467, + "L", + 162, + 467, + "Z", + "M", + 163, + 467, + "L", + 305, + 467, + "L", + 305, + 468, + "L", + 163, + 468, + "Z", + "M", + 165, + 468, + "L", + 303, + 468, + "L", + 303, + 469, + "L", + 165, + 469, + "Z", + "M", + 166, + 469, + "L", + 302, + 469, + "L", + 302, + 470, + "L", + 166, + 470, + "Z", + "M", + 167, + 470, + "L", + 301, + 470, + "L", + 301, + 471, + "L", + 167, + 471, + "Z", + "M", + 169, + 471, + "L", + 299, + 471, + "L", + 299, + 472, + "L", + 169, + 472, + "Z", + "M", + 171, + 472, + "L", + 297, + 472, + "L", + 297, + 473, + "L", + 171, + 473, + "Z", + "M", + 173, + 473, + "L", + 295, + 473, + "L", + 295, + 474, + "L", + 173, + 474, + "Z", + "M", + 177, + 474, + "L", + 291, + 474, + "L", + 291, + 475, + "L", + 177, + 475, + "Z", + "M", + 184, + 475, + "L", + 284, + 475, + "L", + 284, + 476, + "L", + 184, + 476, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 184, + 344, + "L", + 312, + 344, + "L", + 312, + 472, + "L", + 184, + 472, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 184, + 344, + "L", + 312, + 344, + "L", + 312, + 472, + "L", + 184, + 472, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 184, + 344, + "L", + 312, + 344, + "L", + 312, + 472, + "L", + 184, + 472, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 168, + 328, + "L", + 328, + 328, + "L", + 328, + 488, + "L", + 168, + 488, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "raster", + "className": ".float.raster", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +
diff --git a/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt new file mode 100644 index 0000000..a189e8c3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/inspector/elements/highlight/highlight-css-shapes-outside-scroll-expected.txt
@@ -0,0 +1,379 @@ +circle{ + "paths": [ + { + "path": [ + "M", + 88, + 8, + "L", + 88, + 8, + "C", + 132, + 8, + 168, + 44, + 168, + 88, + "L", + 168, + 88, + "C", + 168, + 132, + 132, + 168, + 88, + 168, + "L", + 88, + 168, + "C", + 44, + 168, + 8, + 132, + 8, + 88, + "L", + 8, + 88, + "C", + 8, + 44, + 44, + 8, + 88, + 8, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 88, + -24, + "L", + 88, + -24, + "C", + 150, + -24, + 200, + 26, + 200, + 88, + "L", + 200, + 88, + "C", + 200, + 150, + 150, + 200, + 88, + 200, + "L", + 88, + 200, + "C", + 26, + 200, + -24, + 150, + -24, + 88, + "L", + -24, + 88, + "C", + -24, + 26, + 26, + -24, + 88, + -24, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 168, + 8, + "L", + 168, + 168, + "L", + 8, + 168, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "circle", + "className": ".float.circle", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +circle{ + "paths": [ + { + "path": [ + "M", + 88, + 8, + "L", + 88, + 8, + "C", + 132, + 8, + 168, + 44, + 168, + 88, + "L", + 168, + 88, + "C", + 168, + 132, + 132, + 168, + 88, + 168, + "L", + 88, + 168, + "C", + 44, + 168, + 8, + 132, + 8, + 88, + "L", + 8, + 88, + "C", + 8, + 44, + 44, + 8, + 88, + 8, + "Z" + ], + "fillColor": "rgba(0, 0, 0, 0)" + }, + { + "path": [ + "M", + 88, + -24, + "L", + 88, + -24, + "C", + 150, + -24, + 200, + 26, + 200, + 88, + "L", + 200, + 88, + "C", + 200, + 150, + 150, + 200, + 88, + 200, + "L", + 88, + 200, + "C", + 26, + 200, + -24, + 150, + -24, + 88, + "L", + -24, + 88, + "C", + -24, + 26, + 26, + -24, + 88, + -24, + "Z" + ], + "fillColor": "rgba(128, 128, 128, 0)" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(255, 0, 0, 0)", + "outlineColor": "rgba(128, 0, 0, 0)", + "name": "content" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 255, 0, 0)", + "name": "padding" + }, + { + "path": [ + "M", + 24, + 24, + "L", + 152, + 24, + "L", + 152, + 152, + "L", + 24, + 152, + "Z" + ], + "fillColor": "rgba(0, 0, 255, 0)", + "name": "border" + }, + { + "path": [ + "M", + 8, + 8, + "L", + 168, + 8, + "L", + 168, + 168, + "L", + 8, + 168, + "Z" + ], + "fillColor": "rgba(255, 255, 255, 0)", + "name": "margin" + } + ], + "showRulers": true, + "showExtensionLines": true, + "elementInfo": { + "tagName": "div", + "idValue": "circle", + "className": ".float.circle", + "nodeWidth": "128", + "nodeHeight": "128" + }, + "displayAsMaterial": false +} +
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png new file mode 100644 index 0000000..696c1fe --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png new file mode 100644 index 0000000..220814d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/as-background-image/svg-as-background-6-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/as-background-image/svg-as-background-6-expected.png new file mode 100644 index 0000000..d09eb55d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/as-background-image/svg-as-background-6-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/carto.net/button-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/carto.net/button-expected.png new file mode 100644 index 0000000..d0caca91 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/carto.net/button-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/custom/dasharrayOrigin-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/custom/dasharrayOrigin-expected.png new file mode 100644 index 0000000..a72010cc --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/custom/dasharrayOrigin-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/custom/fractional-rects-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/custom/fractional-rects-expected.png new file mode 100644 index 0000000..ff2768b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/custom/fractional-rects-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/custom/rounded-rects-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/custom/rounded-rects-expected.png new file mode 100644 index 0000000..9e89c381 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/custom/rounded-rects-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/001-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/001-expected.png new file mode 100644 index 0000000..bdf998b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/002-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/002-expected.png new file mode 100644 index 0000000..bf8d289 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/hixie/perf/002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png index 0da4ae8..348cd43 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png index 123207e..95a87ac 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png index 96afef2..09b9eba4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/masking/clip-path-inset-corners-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/masking/clip-path-inset-corners-expected.png index ad3006f..a5f27ad6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/css3/masking/clip-path-inset-corners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/css3/masking/clip-path-inset-corners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/borderRadiusAllStylesAllCorners-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/borderRadiusAllStylesAllCorners-expected.png index 0310b31..4bcc152 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/borderRadiusAllStylesAllCorners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/borderRadiusAllStylesAllCorners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png index b2025cb..13fd9e7 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png index 9498fea..9199a49 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-subpixel-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/masking/clip-path-inset-large-radii-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/masking/clip-path-inset-large-radii-expected.png index 1463895..524ccb9 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/masking/clip-path-inset-large-radii-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/masking/clip-path-inset-large-radii-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png index eb142f5..40bee473e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png index 0fb227d..fead56a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/keyboard-events-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/plugins/keyboard-events-expected.txt deleted file mode 100644 index bf544a83..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/plugins/keyboard-events-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (12, 12) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (12, 12) -CONSOLE MESSAGE: line 22: PLUGIN: keyDown 'a' -CONSOLE MESSAGE: line 22: PLUGIN: keyUp 'a' -CONSOLE MESSAGE: line 23: PLUGIN: keyDown 'b' -CONSOLE MESSAGE: line 23: PLUGIN: keyUp 'b' -CONSOLE MESSAGE: line 24: PLUGIN: keyDown 'c' -CONSOLE MESSAGE: line 24: PLUGIN: keyUp 'c' - -This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for Bug 34936.
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-expected.txt deleted file mode 100644 index 72fd68c..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (12, 12) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (12, 12) -CONSOLE MESSAGE: line 21: PLUGIN: mouseDown at (22, 22) -CONSOLE MESSAGE: line 23: PLUGIN: mouseUp at (32, 22) - -Test for bug 11517: Flash clicks/interactivity not working properly.
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-fixedpos-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-fixedpos-expected.txt deleted file mode 100644 index a15aa1a..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/plugins/mouse-events-fixedpos-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 39: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 39: PLUGIN: mouseDown at (50, 50) -CONSOLE MESSAGE: line 40: PLUGIN: mouseUp at (50, 50) -CONSOLE MESSAGE: line 42: PLUGIN: mouseDown at (60, 60) -CONSOLE MESSAGE: line 44: PLUGIN: mouseUp at (70, 60) - -Tests for widget positions being correctly updated after scrolling. rdar://problem/7559069
diff --git a/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-type-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-type-change-expected.txt index 4c943d2..d7998f4f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-type-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/plugins/webview-plugin-type-change-expected.txt
@@ -4,5 +4,6 @@ LayoutBlockFlow {HTML} at (0,0) size 800x173 LayoutBlockFlow {BODY} at (8,8) size 784x157 LayoutText {#text} at (0,0) size 0x0 + LayoutText {#text} at (0,0) size 0x0 layer at (8,8) size 152x152 LayoutEmbeddedObject {EMBED} at (0,0) size 152x152 [border: (1px solid #000000)]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png index 696c1fe..64e3af9 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png index 220814d..06e05ea5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png index d09eb55d..51ea8b14 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/button-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/button-expected.png index d0caca91..52a0c60 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/button-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/carto.net/button-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/001-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/001-expected.png index bdf998b..9309541 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/002-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/002-expected.png index bf8d289..2ac73f2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png index 0243a42..d61ef55d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png index 3d791af8..ac823e5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png index 3d791af8..ac823e5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png index c122fd2..a847a8e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png index b42cb04..45bf9bd 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png index b1bc2bb..d132c0a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png index fbbe496..19289c7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png index f9faaf07..06c7c4ac 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png index 9c16693..837e744 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png index ac74d3a..3c377645 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png index 0c8d37f8..51ce71ea 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png index 22e209e..2379bba3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png index 21ce74ab..5b84523b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/month-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png index dcdd4eca..566fa88 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png index 76b21b0..da9aa3b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/calendar-picker/week-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/date/date-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/date/date-appearance-basic-expected.png index f3a4b19..d81259b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/date/date-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/date/date-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png index 1812d84..988f4276 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/input-appearance-height-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search-cancel-button-style-sharing-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search-cancel-button-style-sharing-expected.png index 8151741..52fec1d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search-cancel-button-style-sharing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search-cancel-button-style-sharing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png index be9ffb4f..dddd965 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/search/search-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png index 548f235..86df03b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png index 8d7427e..33dd8f9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png index 510aa85..4d38d5d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png index 9e5c4e7..0a18cd4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png index d17bfa7..821076f1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png index dfe3cab31..3c5fb99 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png index 62d2e68..0c98c46b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png index c1fce7f..a969369 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png index 16ab4a0..1a8e5a3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png index 2ea4ec0..bdd2ae0a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png index 84eb9242..12d7dac 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png index 2d732ca..0d766a5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png index 512a070..f14e786 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png index aaef2ae..a1cab78 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png index 3eb89a18..c4081e6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png index 01a7a510..0a5e4006 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png index 8940111..87642d23 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png index dd8c75f..48c013b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png index b2d4afba..5a83912 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png index 79c97e4..96643b6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png index 68e55323..780556c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png index b2f519c..c8f262f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png index 3f6302433..08ea838 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png index f14a7b4..c7c4717 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png index bbcb77d..de2f1de 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png index 7645b2dd..82adc5b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/month-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png index c89521f..f3dd6ff 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png index ad6abaa1..94e2197 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/calendar-picker/week-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/date/date-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/date/date-appearance-basic-expected.png index 926531f..2636efad 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/date/date-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/date/date-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png index 7ea2140..cf51d73 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/input-appearance-height-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search-cancel-button-style-sharing-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search-cancel-button-style-sharing-expected.png index 58b38d2..058536033 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search-cancel-button-style-sharing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search-cancel-button-style-sharing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png index 13caeaf..89dcbbb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/search/search-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png index 4e6d253..7c7a763 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png index 27e8a60..aef78d1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png index 2df57cc..8b4e49e4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png index 352fc9e..80451ee 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png index 0863e0b..f752825 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png index 4d720a2..923f675a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png index 2b67a10..7e0c817 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png index 95c00d7..b637905 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png index d927d42c3..9e75af3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png index ca6a6c9..7bc92fd0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png index 948290c..51b190a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png index 264db1d..7d608d9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png index d037c732..f8ef61b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png index 819459c3..73be9ac 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png index 637c252..5d179c43 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png index 4b36433a..dd6db84 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/mouse-click-plugin-clears-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/mouse-click-plugin-clears-selection-expected.txt index 7e45cf0..578a6b5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/mouse-click-plugin-clears-selection-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/plugins/mouse-click-plugin-clears-selection-expected.txt
@@ -1,3 +1,6 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (52,52) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (52,52) layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png index cdec9db..5500a0e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png index e454f52e..8e15217 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png index 00aa559..d1ac5224 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png index d221397..654f4fc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png index 29739ba..3f072c2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png index c496f40..bf5046e65 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png index b0838f2..67774466 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png index 771062e..b3b30e25 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png index fe25049e..65f3d536 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png index d6365b4..e9a206b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png index 42f9345..af4e93c2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png index 9c7dc22..27f8cb5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png index cbae14f..db1965e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png index 06e3b2fa..36513bcb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png index 69dd643..606521a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/month-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png index 506c3fe5..0bb50668 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png index 73cfcf1..db4c9f56 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/calendar-picker/week-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/date/date-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/date/date-appearance-basic-expected.png index 7daf8e0f..301df52 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/date/date-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/date/date-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png index f32f4ab..d085f6b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/input-appearance-height-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search-cancel-button-style-sharing-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search-cancel-button-style-sharing-expected.png index fc6ac65d..6d370f9f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search-cancel-button-style-sharing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search-cancel-button-style-sharing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png index 97d3b96..d2cb102 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/search/search-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png index 00de2f2..3cb9795 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png index d9b82022..d5e43be 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png index 6c8a4edc..8a9e978 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png index d91c1c6..506a2beb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png index 277d8e95..cb0a13b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png index cdd7cf17..cc8a779 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png index d0adc32..39d07f5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png index 7600634..80c7685 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png index d028d8ba..cb9f500 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png index 72e9b49..74c94a30 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png index 1467888..ccd71bd4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png index b19cc16..a8003a03 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png index fce2d7d..f130cd2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png index c87e974..112b0046 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png index 8bd7de2e..7e2f561 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png index 813d040b..bc3e07d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png index 82c599e4..df65f40 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/clip-path-inset-corners-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/clip-path-inset-corners-expected.png index 031fe7d4..738f270 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/clip-path-inset-corners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/clip-path-inset-corners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/borderRadiusAllStylesAllCorners-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/borderRadiusAllStylesAllCorners-expected.png index 1baafd1..59c62091 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/borderRadiusAllStylesAllCorners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/borderRadiusAllStylesAllCorners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png index c1f591d..3387f96 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png index 96d64d1..6faa863 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/inset-subpixel-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png index de20db4d6..7e7e9cd4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/dom/HTMLInputElement/input-slider-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png index f7e7099..66456c5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png index 8fee11b..b9c3a55 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png index 02a00bd1..b31243a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png index 0431debf..a5f09481 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png index 0eebfd78..65cad2e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png index a1614c6..e3273e44 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png index 38b3a6aa..8407367 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png index e723670..98a38286 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png index 588d168..35e92a3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/month-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png index c1218103..f8f27f21 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png index 1b89e44..99703fdd 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/calendar-picker/week-picker-appearance-step-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png index 7afe1a71..a04d2b9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png index 5aec100..d161adb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png index 3e12100..0291ae5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/date/date-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/date/date-appearance-basic-expected.png index d96547b9..978044a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/date/date-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/date/date-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png index b8181e28..18bad50 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/input-appearance-height-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png index 2f683f3..b91ddbe 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/input-appearance-range-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png index ceedffe..d3153fd 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png index f043b43..f850aea 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/range-focus-by-mouse-then-keydown-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png index cfd8452..c6ae8fd 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-padding-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png index 27ee672..cf19a56 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/range/slider-thumb-shared-style-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search-cancel-button-style-sharing-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search-cancel-button-style-sharing-expected.png index 797dbfb..6dabd990 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search-cancel-button-style-sharing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search-cancel-button-style-sharing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png index 6660b55..2f92a0c0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/search/search-appearance-basic-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png index e8af132..50ef69b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png index 90b3bfc..344824d2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png index d4e3475..df894b7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png index acc5ea47..e3411c5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png index 329d8d4..c73e0fe 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png index f185632c..4bf6924 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png index 947e5cff..2f2eede 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png index 1f923e9..2805b95e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png index 584ec89..b6ab1a4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png index b39845a..3d61b46 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png index 3474357..d4c1466f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png index 1ca467e..85b3273 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png index 07ed084..2e00afc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png index c4d02ad..42ebda2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png index f9bab5a6..40f19e0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png index 4d6bddb5..986b6f11 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/masking/clip-path-inset-large-radii-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/masking/clip-path-inset-large-radii-expected.png index aa3cd7d1..30fe1de 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/masking/clip-path-inset-large-radii-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/masking/clip-path-inset-large-radii-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png index de20db4d6..7e7e9cd4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/slider-thumb-drag-release-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png index 5d8d496..ef5ba56a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png index 578abfb6..da4b8ec5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/keyboard-events-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/keyboard-events-expected.txt deleted file mode 100644 index bf544a83..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/keyboard-events-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (12, 12) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (12, 12) -CONSOLE MESSAGE: line 22: PLUGIN: keyDown 'a' -CONSOLE MESSAGE: line 22: PLUGIN: keyUp 'a' -CONSOLE MESSAGE: line 23: PLUGIN: keyDown 'b' -CONSOLE MESSAGE: line 23: PLUGIN: keyUp 'b' -CONSOLE MESSAGE: line 24: PLUGIN: keyDown 'c' -CONSOLE MESSAGE: line 24: PLUGIN: keyUp 'c' - -This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for Bug 34936.
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-click-plugin-clears-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-click-plugin-clears-selection-expected.txt index 8fb9dc1..b129b69f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-click-plugin-clears-selection-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-click-plugin-clears-selection-expected.txt
@@ -1,3 +1,6 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (52,52) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (52,52) layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-expected.txt deleted file mode 100644 index 72fd68c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (12, 12) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (12, 12) -CONSOLE MESSAGE: line 21: PLUGIN: mouseDown at (22, 22) -CONSOLE MESSAGE: line 23: PLUGIN: mouseUp at (32, 22) - -Test for bug 11517: Flash clicks/interactivity not working properly.
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-fixedpos-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-fixedpos-expected.txt deleted file mode 100644 index a15aa1a..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/mouse-events-fixedpos-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 39: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 39: PLUGIN: mouseDown at (50, 50) -CONSOLE MESSAGE: line 40: PLUGIN: mouseUp at (50, 50) -CONSOLE MESSAGE: line 42: PLUGIN: mouseDown at (60, 60) -CONSOLE MESSAGE: line 44: PLUGIN: mouseUp at (70, 60) - -Tests for widget positions being correctly updated after scrolling. rdar://problem/7559069
diff --git a/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-initiate-popup-window-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-initiate-popup-window-expected.txt index 8e6319c..3730ca9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-initiate-popup-window-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/plugins/plugin-initiate-popup-window-expected.txt
@@ -1,6 +1,6 @@ CONSOLE MESSAGE: line 67: PLUGIN: getFocusEvent CONSOLE MESSAGE: line 17: window count: 1 -CONSOLE MESSAGE: line 21: PLUGIN: getFocusEvent +CONSOLE MESSAGE: line 20: PLUGIN: getFocusEvent CONSOLE MESSAGE: line 21: PLUGIN: getFocusEvent CONSOLE MESSAGE: line 21: PLUGIN: mouseDown at (12, 12) CONSOLE MESSAGE: line 30: window count: 2
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png index 998ad49..bce4793 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png index d4853cf..a5d36503 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png index 70b7e1c0..dc23d2c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/button-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/button-expected.png index f53de0e..89c4af8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/button-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/carto.net/button-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/001-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/001-expected.png index 2d6e456..65a04fc1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/002-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/002-expected.png index 2e190e0..544e3823 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png index b90d50c..3b54e4c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png index 8a2d8bb9..fa7e2a1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png index 8a2d8bb9..fa7e2a1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png index 2b09d40..e638b4a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png index de20db4d6..7e7e9cd4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/slider-thumb-drag-release-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png index 9e8cf50..b4da4989 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png index 30305ae1..0bbd60b9 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png index 768c0ab..2030f65 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/css3/masking/clip-path-inset-corners-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/css3/masking/clip-path-inset-corners-expected.png index 5b9976b..f9b69a9d 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/css3/masking/clip-path-inset-corners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/css3/masking/clip-path-inset-corners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/borderRadiusAllStylesAllCorners-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/borderRadiusAllStylesAllCorners-expected.png index adc35ae..439e8ae 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/borderRadiusAllStylesAllCorners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/borders/borderRadiusAllStylesAllCorners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png index 06c5749..4ed0cde 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png index a48285e..ff7699c1 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/box-shadow/inset-subpixel-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/masking/clip-path-inset-large-radii-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/masking/clip-path-inset-large-radii-expected.png index 569f8bf..8b6192e 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/masking/clip-path-inset-large-radii-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/masking/clip-path-inset-large-radii-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png index eeb8b5d4..54014b1 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png index 385b112..b63299ed 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/mouse-click-plugin-clears-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/mouse-click-plugin-clears-selection-expected.txt index a8e67f20..073c8a63b 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/mouse-click-plugin-clears-selection-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/mouse-click-plugin-clears-selection-expected.txt
@@ -1,3 +1,6 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (52,52) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (52,52) layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-type-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-type-change-expected.txt index 4c943d2..d7998f4f 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-type-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/plugins/webview-plugin-type-change-expected.txt
@@ -4,5 +4,6 @@ LayoutBlockFlow {HTML} at (0,0) size 800x173 LayoutBlockFlow {BODY} at (8,8) size 784x157 LayoutText {#text} at (0,0) size 0x0 + LayoutText {#text} at (0,0) size 0x0 layer at (8,8) size 152x152 LayoutEmbeddedObject {EMBED} at (0,0) size 152x152 [border: (1px solid #000000)]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png index 360c2f5..ee2ad0f 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png index 0c247f4..0c2a191 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/as-background-image/svg-as-background-6-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/as-background-image/svg-as-background-6-expected.png index f41596a..853a7f12 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/as-background-image/svg-as-background-6-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/as-background-image/svg-as-background-6-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/carto.net/button-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/carto.net/button-expected.png index c584007d..aa72158 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/carto.net/button-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/carto.net/button-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/001-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/001-expected.png index 367ed36..f1f072f28 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/002-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/002-expected.png index 2a966ab..698a9bb8 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/perf/002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png index 3a89890..d40e05c 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png index b74b5be..c40807b 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png index b74b5be..c40807b 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png index e13f66b..240470a 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png index 8f8b55b3..c503e62b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-pixel-transparent-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png index ca56525..507d21c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png index 669c9255..1b0da0f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-squashing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/masking/clip-path-inset-corners-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/masking/clip-path-inset-corners-expected.png index b8de51f..d6b5675 100644 --- a/third_party/WebKit/LayoutTests/platform/win/css3/masking/clip-path-inset-corners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/css3/masking/clip-path-inset-corners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/borderRadiusAllStylesAllCorners-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/borderRadiusAllStylesAllCorners-expected.png index 92b7965..94084b0a 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/borderRadiusAllStylesAllCorners-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/borderRadiusAllStylesAllCorners-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png index 283daead..a11abb0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png index 65b14ce0..4a1b9736 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/masking/clip-path-inset-large-radii-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/masking/clip-path-inset-large-radii-expected.png index 37912023..2d41a2d 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/masking/clip-path-inset-large-radii-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/masking/clip-path-inset-large-radii-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png index 407dfa8..8368ca6 100644 --- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png index f757eb8..d2f2132 100644 --- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/border-radius-style-002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/keyboard-events-expected.txt b/third_party/WebKit/LayoutTests/platform/win/plugins/keyboard-events-expected.txt deleted file mode 100644 index ea26d0a..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/plugins/keyboard-events-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (20, 20) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (20, 20) -CONSOLE MESSAGE: line 22: PLUGIN: keyDown 'A' -CONSOLE MESSAGE: line 22: PLUGIN: keyUp 'A' -CONSOLE MESSAGE: line 23: PLUGIN: keyDown 'B' -CONSOLE MESSAGE: line 23: PLUGIN: keyUp 'B' -CONSOLE MESSAGE: line 24: PLUGIN: keyDown 'C' -CONSOLE MESSAGE: line 24: PLUGIN: keyUp 'C' - -This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for Bug 34936.
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-click-plugin-clears-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-click-plugin-clears-selection-expected.txt index 37adf19..0d471171 100644 --- a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-click-plugin-clears-selection-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-click-plugin-clears-selection-expected.txt
@@ -1,3 +1,6 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (52,52) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (52,52) layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-expected.txt b/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-expected.txt deleted file mode 100644 index daade43..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 18: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 18: PLUGIN: mouseDown at (20, 20) -CONSOLE MESSAGE: line 19: PLUGIN: mouseUp at (20, 20) -CONSOLE MESSAGE: line 21: PLUGIN: mouseDown at (30, 30) -CONSOLE MESSAGE: line 23: PLUGIN: mouseUp at (40, 30) - -Test for bug 11517: Flash clicks/interactivity not working properly.
diff --git a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-fixedpos-expected.txt b/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-fixedpos-expected.txt deleted file mode 100644 index a2b3855..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/plugins/mouse-events-fixedpos-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -CONSOLE MESSAGE: line 39: PLUGIN: getFocusEvent -CONSOLE MESSAGE: line 39: PLUGIN: mouseDown at (90, 90) -CONSOLE MESSAGE: line 40: PLUGIN: mouseUp at (90, 90) -CONSOLE MESSAGE: line 42: PLUGIN: mouseDown at (100, 100) -CONSOLE MESSAGE: line 44: PLUGIN: mouseUp at (110, 100) - -Tests for widget positions being correctly updated after scrolling. rdar://problem/7559069
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png index 9907860..05ca7d95 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png index 46a363d..c194b80b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/shapes-rect-02-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-6-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-6-expected.png index b3bb6a0d..31236902 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-6-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-background-image/svg-as-background-6-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/button-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/button-expected.png index 60ca575..f840c96 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/button-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/carto.net/button-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/001-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/001-expected.png index 0cf800e..f074a66 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/002-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/002-expected.png index 5c52b4e..a67bb158 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/002-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/002-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png index 49018d8..e1bf258 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/wicd/test-scalable-background-image1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png index 7a8ed66..9355425 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png index 7a8ed66..9355425 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-absolute-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png index 1a567ab..26f13d5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-svg-through-object-with-percentage-size-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/plugins/keyboard-events-expected.txt b/third_party/WebKit/LayoutTests/plugins/keyboard-events-expected.txt new file mode 100644 index 0000000..50d9acf --- /dev/null +++ b/third_party/WebKit/LayoutTests/plugins/keyboard-events-expected.txt
@@ -0,0 +1,11 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (12,12) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (12,12) +CONSOLE MESSAGE: Blink Test Plugin: KeyDown 'KeyA' +CONSOLE MESSAGE: Blink Test Plugin: KeyUp 'KeyA' +CONSOLE MESSAGE: Blink Test Plugin: KeyDown 'KeyB' +CONSOLE MESSAGE: Blink Test Plugin: KeyUp 'KeyB' +CONSOLE MESSAGE: Blink Test Plugin: KeyDown 'KeyC' +CONSOLE MESSAGE: Blink Test Plugin: KeyUp 'KeyC' + +This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for Bug 34936.
diff --git a/third_party/WebKit/LayoutTests/plugins/keyboard-events.html b/third_party/WebKit/LayoutTests/plugins/keyboard-events.html index 51b773d6..800a3bb 100644 --- a/third_party/WebKit/LayoutTests/plugins/keyboard-events.html +++ b/third_party/WebKit/LayoutTests/plugins/keyboard-events.html
@@ -1,31 +1,31 @@ +<!DOCTYPE html> <html> -<body> -<embed name="plg" type="application/x-webkit-test-netscape" windowedPlugin="false" width=100 height=100></embed> -<p>This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for <a href="https://bugs.webkit.org/show_bug.cgi?id=34936">Bug 34936</a>.</p> +<head> +<script src="../resources/plugin.js"></script> <script> - - plg.windowedPlugin = false; - plg.eventLoggingEnabled = true; - +startAfterLoadAndFinish(function () { if (!window.testRunner) { - document.write("This test does not work in manual mode."); - } else { - testRunner.dumpAsText(); - - // Send a mouse-click event to set the input focus to the test plugin. - eventSender.mouseMoveTo(0,0); - eventSender.mouseMoveTo(20,20); - eventSender.mouseDown(); - eventSender.mouseUp(); - - // Send keyboard events to the plugin. - eventSender.keyDown('a'); - eventSender.keyDown('b'); - eventSender.keyDown('c'); + document.body.appendChild(document.createTextNode("This test does not work in manual mode.")); + return; } - plg.eventLoggingEnabled = false; // stop logging so our output doesn't bleed into the next test + testRunner.dumpAsText(); + // Send a mouse-click event to set the input focus to the test plugin. + eventSender.mouseMoveTo(0,0); + eventSender.mouseMoveTo(20,20); + eventSender.mouseDown(); + eventSender.mouseUp(); + + // Send keyboard events to the plugin. + eventSender.keyDown('a'); + eventSender.keyDown('b'); + eventSender.keyDown('c'); +}); </script> +</head> +<body> +<embed type="application/x-blink-test-plugin" width=100 height=100></embed> +<p>This test checks if a plugin can receive keyboard events sent from eventSender. This is a test for <a href="https://bugs.webkit.org/show_bug.cgi?id=34936">Bug 34936</a>.</p> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/plugins/mouse-click-plugin-clears-selection.html b/third_party/WebKit/LayoutTests/plugins/mouse-click-plugin-clears-selection.html index 33f80d87..9b41982 100644 --- a/third_party/WebKit/LayoutTests/plugins/mouse-click-plugin-clears-selection.html +++ b/third_party/WebKit/LayoutTests/plugins/mouse-click-plugin-clears-selection.html
@@ -18,7 +18,7 @@ </script> </head> <body> -<embed id="plg" type="application/x-webkit-test-netscape" width="100" height="100" windowedplugin="false"></embed><br> +<embed type="application/x-blink-test-plugin" width="100" height="100"></embed><br> <input id="frame" value="hello"/> <div id="output"></div> </body>
diff --git a/third_party/WebKit/LayoutTests/plugins/mouse-events-expected.txt b/third_party/WebKit/LayoutTests/plugins/mouse-events-expected.txt new file mode 100644 index 0000000..3b793d0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/plugins/mouse-events-expected.txt
@@ -0,0 +1,7 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (12,12) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (12,12) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (22,22) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (32,22) + +Test for bug 11517: Flash clicks/interactivity not working properly.
diff --git a/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos-expected.txt b/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos-expected.txt new file mode 100644 index 0000000..ac331bf --- /dev/null +++ b/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos-expected.txt
@@ -0,0 +1,7 @@ +CONSOLE MESSAGE: Blink Test Plugin: DidChangeFocus(true) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (50,50) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (50,50) +CONSOLE MESSAGE: Blink Test Plugin: MouseDown at (60,60) +CONSOLE MESSAGE: Blink Test Plugin: MouseUp at (70,60) + +Tests for widget positions being correctly updated after scrolling. rdar://problem/7559069
diff --git a/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos.html b/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos.html index ecace9f..41010d4 100644 --- a/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos.html +++ b/third_party/WebKit/LayoutTests/plugins/mouse-events-fixedpos.html
@@ -1,27 +1,28 @@ +<!DOCTYPE html> <html> -<style type="text/css" media="screen"> - body { +<head> +<style> +body { height: 1000px; - } +} - .fixed { +.fixed { position: fixed; left: 20px; top: 20px; - } +} - p { +p { margin-top: 200px; - } +} - embed { +embed { margin: 20px; - } +} </style> +<script src="../resources/plugin.js"></script> <script> - - function runTest() - { +startAfterLoadAndFinish(function () { window.scrollBy(50, 50); if (!window.testRunner) { @@ -31,9 +32,6 @@ testRunner.dumpAsText(); - plg.windowedPlugin = false; - plg.eventLoggingEnabled = true; - eventSender.mouseMoveTo(70,70); eventSender.mouseMoveTo(90,90); eventSender.mouseDown(); @@ -43,17 +41,13 @@ eventSender.mouseMoveTo(110,100); eventSender.mouseUp(); eventSender.mouseMoveTo(20,20); - - plg.eventLoggingEnabled = false; // stop logging so our output doesn't bleed into the next test - } - - window.addEventListener('load', runTest, false); +}); </script> +</head> <body> - <div class="fixed"> - <embed name="plg" type="application/x-webkit-test-netscape" windowedPlugin="false" width=100 height=100></embed> - </div> - +<div class="fixed"> + <embed type="application/x-blink-test-plugin" width=100 height=100></embed> +</div> <p>Tests for widget positions being correctly updated after scrolling. <a href="rdar://problem/7559069">rdar://problem/7559069</a></p> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/plugins/mouse-events.html b/third_party/WebKit/LayoutTests/plugins/mouse-events.html index 60053fa..916724ee 100644 --- a/third_party/WebKit/LayoutTests/plugins/mouse-events.html +++ b/third_party/WebKit/LayoutTests/plugins/mouse-events.html
@@ -1,31 +1,31 @@ +<!DOCTYPE html> <html> -<body> -<embed name="plg" type="application/x-webkit-test-netscape" windowedPlugin="false" width=100 height=100></embed> -<p>Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=11517">bug 11517</a>: -Flash clicks/interactivity not working properly.</p> +<head> +<script src="../resources/plugin.js"></script> <script> - - plg.windowedPlugin = false; - plg.eventLoggingEnabled = true; - +startAfterLoadAndFinish(function () { if (!window.testRunner) { - document.write("This test does not work in manual mode."); - } else { - testRunner.dumpAsText(); - - eventSender.mouseMoveTo(0,0); - eventSender.mouseMoveTo(20,20); - eventSender.mouseDown(); - eventSender.mouseUp(); - eventSender.mouseMoveTo(30,30); - eventSender.mouseDown(); - eventSender.mouseMoveTo(40,30); - eventSender.mouseUp(); - eventSender.mouseMoveTo(0,0); + document.body.appendChild(document.createTextNode("This test does not work in manual mode.")); + return; } - plg.eventLoggingEnabled = false; // stop logging so our output doesn't bleed into the next test + testRunner.dumpAsText(); + eventSender.mouseMoveTo(0,0); + eventSender.mouseMoveTo(20,20); + eventSender.mouseDown(); + eventSender.mouseUp(); + eventSender.mouseMoveTo(30,30); + eventSender.mouseDown(); + eventSender.mouseMoveTo(40,30); + eventSender.mouseUp(); + eventSender.mouseMoveTo(0,0); +}); </script> +</head> +<body> +<embed type="application/x-blink-test-plugin" width=100 height=100></embed> +<p>Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=11517">bug 11517</a>: +Flash clicks/interactivity not working properly.</p> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.png b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.png index a7a92d27..4f54491 100644 --- a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.png +++ b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.txt b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.txt index a87dd4f..bf72730 100644 --- a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.txt +++ b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change-expected.txt
@@ -4,5 +4,6 @@ LayoutBlockFlow {HTML} at (0,0) size 800x172 LayoutBlockFlow {BODY} at (8,8) size 784x156 LayoutText {#text} at (0,0) size 0x0 + LayoutText {#text} at (0,0) size 0x0 layer at (8,8) size 152x152 LayoutEmbeddedObject {EMBED} at (0,0) size 152x152 [border: (1px solid #000000)]
diff --git a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change.html b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change.html index 6441b55..34b05da 100644 --- a/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change.html +++ b/third_party/WebKit/LayoutTests/plugins/webview-plugin-type-change.html
@@ -8,18 +8,15 @@ </style> <embed id="plugin"></embed> <script> +document.querySelector('embed').addEventListener('message', function(message) { + if (message.data == 'loaded') + if (window.testRunner) + window.testRunner.notifyDone(); +}); onload = function() { - document.getElementById("plugin").setAttribute('type', 'application/x-webkit-test-netscape'); + document.getElementById('plugin').setAttribute('type', 'application/x-blink-test-plugin'); - if (window.testRunner) { + if (window.testRunner) window.testRunner.waitUntilDone(); - // Need to paint two frames in order to allow the plugin to propery load. - // TODO(chrishtr): find out why and fix. - window.testRunner.layoutAndPaintAsyncThen(function() { - window.testRunner.layoutAndPaintAsyncThen(function() { - window.testRunner.notifyDone(); - }); - }); - } } -</script> \ No newline at end of file +</script>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/dasharrayOrigin-expected.png b/third_party/WebKit/LayoutTests/svg/custom/dasharrayOrigin-expected.png index a72010cc..30d87bc 100644 --- a/third_party/WebKit/LayoutTests/svg/custom/dasharrayOrigin-expected.png +++ b/third_party/WebKit/LayoutTests/svg/custom/dasharrayOrigin-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/fractional-rects-expected.png b/third_party/WebKit/LayoutTests/svg/custom/fractional-rects-expected.png index ff2768b..e707e29 100644 --- a/third_party/WebKit/LayoutTests/svg/custom/fractional-rects-expected.png +++ b/third_party/WebKit/LayoutTests/svg/custom/fractional-rects-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/gradient-rotated-bbox-expected.png b/third_party/WebKit/LayoutTests/svg/custom/gradient-rotated-bbox-expected.png index cfc98e1..07b48abc 100644 --- a/third_party/WebKit/LayoutTests/svg/custom/gradient-rotated-bbox-expected.png +++ b/third_party/WebKit/LayoutTests/svg/custom/gradient-rotated-bbox-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/rounded-rects-expected.png b/third_party/WebKit/LayoutTests/svg/custom/rounded-rects-expected.png index 9e89c381..c9068ef 100644 --- a/third_party/WebKit/LayoutTests/svg/custom/rounded-rects-expected.png +++ b/third_party/WebKit/LayoutTests/svg/custom/rounded-rects-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/mouse-pointer-event-properties-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/mouse-pointer-event-properties-expected.txt index c29e311..d78ebb9 100644 --- a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/mouse-pointer-event-properties-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/mouse-pointer-event-properties-expected.txt
@@ -10,7 +10,7 @@ PASS lastPointerEvent.type is "pointerover" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -34,7 +34,7 @@ PASS lastPointerEvent.type is "pointerenter" PASS lastPointerEvent.bubbles is false PASS lastPointerEvent.cancelable is false -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -58,7 +58,7 @@ PASS lastPointerEvent.type is "pointermove" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -84,7 +84,7 @@ PASS lastPointerEvent.type is "pointermove" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 25 PASS lastPointerEvent.clientY is 41 @@ -108,7 +108,7 @@ PASS lastPointerEvent.type is "pointermove" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -134,7 +134,7 @@ PASS lastPointerEvent.type is "pointerdown" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -158,7 +158,7 @@ PASS lastPointerEvent.type is "pointerup" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -182,7 +182,7 @@ PASS lastPointerEvent.type is "pointerdown" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -206,7 +206,7 @@ PASS lastPointerEvent.type is "pointerup" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -230,7 +230,7 @@ PASS lastPointerEvent.type is "pointerdown" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -254,7 +254,7 @@ PASS lastPointerEvent.type is "pointerup" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 23 PASS lastPointerEvent.clientY is 31 @@ -612,7 +612,7 @@ PASS lastPointerEvent.type is "pointerout" PASS lastPointerEvent.bubbles is true PASS lastPointerEvent.cancelable is true -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 13 PASS lastPointerEvent.clientY is 21 @@ -636,7 +636,7 @@ PASS lastPointerEvent.type is "pointerleave" PASS lastPointerEvent.bubbles is false PASS lastPointerEvent.cancelable is false -PASS lastPointerEvent.pointerId is 0 +PASS lastPointerEvent.pointerId is 1 PASS lastPointerEvent.isPrimary is true PASS lastPointerEvent.clientX is 13 PASS lastPointerEvent.clientY is 21
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-event-properties-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-event-properties-expected.txt index e3bb63b..1394201 100644 --- a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-event-properties-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-event-properties-expected.txt
@@ -2,18 +2,18 @@ This is a testharness.js-based test. PASS Pointer property propagation from touches to PointerEvents -PASS Pointer event properties for pointer 0 on pointerdown PASS Pointer event properties for pointer 1 on pointerdown PASS Pointer event properties for pointer 2 on pointerdown PASS Pointer event properties for pointer 3 on pointerdown -PASS Pointer event properties for pointer 0 on pointermove +PASS Pointer event properties for pointer 4 on pointerdown PASS Pointer event properties for pointer 1 on pointermove PASS Pointer event properties for pointer 2 on pointermove PASS Pointer event properties for pointer 3 on pointermove -PASS Pointer event properties for pointer 0 on pointerup +PASS Pointer event properties for pointer 4 on pointermove PASS Pointer event properties for pointer 1 on pointerup PASS Pointer event properties for pointer 2 on pointerup PASS Pointer event properties for pointer 3 on pointerup +PASS Pointer event properties for pointer 4 on pointerup PASS Received pointer events Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-events-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-events-expected.txt index aa4813e..8660766d 100644 --- a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-events-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointer-events-expected.txt
@@ -56,28 +56,28 @@ --- test PE isPrimary values --- green received pointerdown at phase=target PASS receivedPEsAtTarget[0].isPrimary is true -receivedPEsAtTarget[0].pointerId=0 +receivedPEsAtTarget[0].pointerId=5 green received pointerdown at phase=target PASS receivedPEsAtTarget[1].isPrimary is false -receivedPEsAtTarget[1].pointerId=1 +receivedPEsAtTarget[1].pointerId=6 green received pointermove at phase=target PASS receivedPEsAtTarget[2].isPrimary is false -PASS receivedPEsAtTarget[2].pointerId is 1 +PASS receivedPEsAtTarget[2].pointerId is 6 green received pointerup at phase=target PASS receivedPEsAtTarget[3].isPrimary is true -PASS receivedPEsAtTarget[3].pointerId is 0 +PASS receivedPEsAtTarget[3].pointerId is 5 green received pointermove at phase=target PASS receivedPEsAtTarget[4].isPrimary is false -PASS receivedPEsAtTarget[4].pointerId is 1 +PASS receivedPEsAtTarget[4].pointerId is 6 green received pointerdown at phase=target PASS receivedPEsAtTarget[5].isPrimary is false -receivedPEsAtTarget[5].pointerId=2 +receivedPEsAtTarget[5].pointerId=7 green received pointerup at phase=target PASS receivedPEsAtTarget[6].isPrimary is false -PASS receivedPEsAtTarget[6].pointerId is 1 +PASS receivedPEsAtTarget[6].pointerId is 6 green received pointerup at phase=target PASS receivedPEsAtTarget[7].isPrimary is false -PASS receivedPEsAtTarget[7].pointerId is 2 +PASS receivedPEsAtTarget[7].pointerId is 7 green received pointerdown at phase=target PASS receivedPEsAtTarget[8].isPrimary is true PASS receivedPEsAtTarget.length is 9
diff --git a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointercancel-expected.txt b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointercancel-expected.txt index 8ce7a45f..889b94e 100644 --- a/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointercancel-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/pointerevent/fast/events/pointerevents/touch-pointercancel-expected.txt
@@ -6,131 +6,131 @@ --- single drag tests --- -- preventDefault on none, without uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=2 Received touchstart, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=2 Received touchmove, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=2 Received touchmove, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=2 Received touchmove, touchIds=0 -Received pointerup, pointerId=0 +Received pointerup, pointerId=2 Received touchend, touchIds=0 -- preventDefault on pointermove, without uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=3 Received touchstart, touchIds=0 -Received pointermove, pointerId=0, prevented default -Received pointermove, pointerId=0, prevented default -Received pointermove, pointerId=0, prevented default -Received pointerup, pointerId=0 +Received pointermove, pointerId=3, prevented default +Received pointermove, pointerId=3, prevented default +Received pointermove, pointerId=3, prevented default +Received pointerup, pointerId=3 Received touchend, touchIds=0 -- preventDefault on touchmove, without uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=4 Received touchstart, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=4 Received touchmove, touchIds=0, prevented default -Received pointermove, pointerId=0 +Received pointermove, pointerId=4 Received touchmove, touchIds=0, prevented default -Received pointermove, pointerId=0 +Received pointermove, pointerId=4 Received touchmove, touchIds=0, prevented default -Received pointerup, pointerId=0 +Received pointerup, pointerId=4 Received touchend, touchIds=0 -- preventDefault on none, with uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=5 Received touchstart, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=5 Received touchmove, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=5 Received touchmove, touchIds=0 -Received pointercancel, pointerId=0 +Received pointercancel, pointerId=5 Received touchmove, touchIds=0 Received touchend, touchIds=0 -- preventDefault on pointermove, with uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=6 Received touchstart, touchIds=0 -Received pointermove, pointerId=0, prevented default -Received pointermove, pointerId=0, prevented default -Received pointercancel, pointerId=0 +Received pointermove, pointerId=6, prevented default +Received pointermove, pointerId=6, prevented default +Received pointercancel, pointerId=6 Received touchmove, touchIds=0 Received touchend, touchIds=0 -- preventDefault on touchmove, with uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 +Received pointerdown, pointerId=7 Received touchstart, touchIds=0 -Received pointermove, pointerId=0 +Received pointermove, pointerId=7 Received touchmove, touchIds=0, prevented default -Received pointermove, pointerId=0 +Received pointermove, pointerId=7 Received touchmove, touchIds=0, prevented default -Received pointermove, pointerId=0 +Received pointermove, pointerId=7 Received touchmove, touchIds=0, prevented default -Received pointerup, pointerId=0 +Received pointerup, pointerId=7 Received touchend, touchIds=0 --- multi drag tests --- -- preventDefault on none, without uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 -Received pointerdown, pointerId=1 -Received pointerdown, pointerId=2 +Received pointerdown, pointerId=8 +Received pointerdown, pointerId=9 +Received pointerdown, pointerId=10 Received touchstart, touchIds=012 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 -Received pointermove, pointerId=2 +Received pointermove, pointerId=8 +Received pointermove, pointerId=9 +Received pointermove, pointerId=10 Received touchmove, touchIds=012 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 -Received pointermove, pointerId=2 +Received pointermove, pointerId=8 +Received pointermove, pointerId=9 +Received pointermove, pointerId=10 Received touchmove, touchIds=012 -Received pointerdown, pointerId=3 +Received pointerdown, pointerId=11 Received touchstart, touchIds=3 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 -Received pointermove, pointerId=2 -Received pointermove, pointerId=3 +Received pointermove, pointerId=8 +Received pointermove, pointerId=9 +Received pointermove, pointerId=10 +Received pointermove, pointerId=11 Received touchmove, touchIds=0123 -Received pointerup, pointerId=0 -Received pointerup, pointerId=1 -Received pointerup, pointerId=2 -Received pointerup, pointerId=3 +Received pointerup, pointerId=8 +Received pointerup, pointerId=9 +Received pointerup, pointerId=10 +Received pointerup, pointerId=11 Received touchend, touchIds=0123 -- preventDefault on none, with uncanceledMoveCausesScroll -- -Received pointerdown, pointerId=0 -Received pointerdown, pointerId=1 -Received pointerdown, pointerId=2 +Received pointerdown, pointerId=12 +Received pointerdown, pointerId=13 +Received pointerdown, pointerId=14 Received touchstart, touchIds=012 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 -Received pointermove, pointerId=2 +Received pointermove, pointerId=12 +Received pointermove, pointerId=13 +Received pointermove, pointerId=14 Received touchmove, touchIds=012 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 -Received pointermove, pointerId=2 +Received pointermove, pointerId=12 +Received pointermove, pointerId=13 +Received pointermove, pointerId=14 Received touchmove, touchIds=012 -Received pointercancel, pointerId=0 -Received pointercancel, pointerId=1 -Received pointercancel, pointerId=2 +Received pointercancel, pointerId=12 +Received pointercancel, pointerId=13 +Received pointercancel, pointerId=14 Received touchstart, touchIds=3 Received touchmove, touchIds=0123 Received touchend, touchIds=0123 --- multi cancel tests --- -Received pointerdown, pointerId=0 -Received pointerdown, pointerId=1 -Received pointerdown, pointerId=2 +Received pointerdown, pointerId=15 +Received pointerdown, pointerId=16 +Received pointerdown, pointerId=17 Received touchstart, touchIds=012 -Received pointercancel, pointerId=2 +Received pointercancel, pointerId=17 Received touchcancel, touchIds=2 -Received pointermove, pointerId=0 -Received pointermove, pointerId=1 +Received pointermove, pointerId=15 +Received pointermove, pointerId=16 Received touchmove, touchIds=01 -Received pointercancel, pointerId=0 -Received pointercancel, pointerId=1 +Received pointercancel, pointerId=15 +Received pointercancel, pointerId=16 Received touchcancel, touchIds=01 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/README.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/README.txt new file mode 100644 index 0000000..4b5631d2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/README.txt
@@ -0,0 +1 @@ +# This suite runs only the tests in this directory with --enable-threaded-compositing.
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change-worker.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change-worker.html similarity index 83% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change-worker.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change-worker.html index afea40b..877f013 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change-worker.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change-worker.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <div id="container"></div> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> var test = async_test("This test checks that a compositor proxy can be mutated from the compositor worker thread.");
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change.html similarity index 77% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change.html index 3722bc2..dd4bc4a 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-attribute-change.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-attribute-change.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <div id="container"></div> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> test(function() {
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html similarity index 86% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html index 31a1a37a..76c3089 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker-terminate.html
@@ -1,8 +1,8 @@ <!DOCTYPE html> <div id="container"></div> -<script src="../../fast/workers/resources/worker-util.js"></script> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../fast/workers/resources/worker-util.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> var test = async_test(function() {
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker.html similarity index 81% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker.html index 2695b45d..a51c1b20 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect-worker.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect-worker.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <div id="container"></div> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> var test = async_test(function() {
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect.html similarity index 79% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect.html index 03991f8..daa6e5559 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-disconnect.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-disconnect.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <div id="container"></div> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> test(function() {
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-postmessage.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-postmessage.html similarity index 91% rename from third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-postmessage.html rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-postmessage.html index 9ab7454..bd57b71 100644 --- a/third_party/WebKit/LayoutTests/fast/compositorworker/compositor-proxy-postmessage.html +++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/compositor-proxy-postmessage.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <div id='container'></div> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> <script> var test = async_test("This test checks that an element's compositor proxy can be sent from the main thread to the compositor thread.");
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-disconnect.js b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-disconnect.js similarity index 100% rename from third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-disconnect.js rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-disconnect.js
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-echo.js b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-echo.js similarity index 100% rename from third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-echo.js rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-echo.js
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-idle.js b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-idle.js similarity index 100% rename from third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-idle.js rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-idle.js
diff --git a/third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-mutate.js b/third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-mutate.js similarity index 100% rename from third_party/WebKit/LayoutTests/fast/compositorworker/resources/proxy-mutate.js rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/compositorworker/resources/proxy-mutate.js
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js index d48f7e8..7f117337 100644 --- a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js +++ b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
@@ -709,12 +709,15 @@ var mismatches = {}; var maxDiff = 0.0; + var maxDiffIndex = 0; for (var i = 0; i < array.length; i++) { var diff = Math.abs(this.target[i] - array[i]); if (diff > maxAllowedError) mismatches[i] = diff; - if (diff > maxDiff) + if (diff > maxDiff) { maxDiff = diff; + maxDiffIndex = i; + } } var numberOfmismatches = Object.keys(mismatches).length; @@ -728,11 +731,14 @@ var counter = 0; var failureMessage = 'does not equal [' + arrStr + '] with an element-wise tolerance of ' + maxAllowedError; + failureMessage += '\nIndex\t Diff\t\t Actual\t\t Expected'; for (var index in mismatches) { - failureMessage += '\n[' + index + '] : ' + mismatches[index]; + failureMessage += '\n[' + index + '] :\t' + mismatches[index] + + '\t' + this.target[index] + '\t' + array[index]; if (++counter >= this.NUM_ERRORS_LOG || counter === numberOfmismatches) { failureMessage += '\nand ' + (numberOfmismatches - counter) + - ' more differences with the maximum error of ' + maxDiff; + ' more differences with the maximum error of ' + maxDiff + + ' at index ' + maxDiffIndex; break; } }
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 0520186..117a8ad 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3124,6 +3124,9 @@ method initKeyboardEvent interface KeyframeEffect : AnimationEffectReadOnly method constructor +interface KeywordValue : StyleValue + getter keywordValue + method constructor interface Location method constructor interface MIDIAccess : EventTarget @@ -5159,6 +5162,10 @@ getter length method constructor method item +interface StyleValue + static method parse + getter cssString + method constructor interface SubtleCrypto method constructor method decrypt
diff --git a/third_party/WebKit/ManualTests/animation/set-to.svg b/third_party/WebKit/ManualTests/animation/set-to.svg deleted file mode 100644 index 8b35459..0000000 --- a/third_party/WebKit/ManualTests/animation/set-to.svg +++ /dev/null
@@ -1,10 +0,0 @@ -<svg xmlns='http://www.w3.org/2000/svg'> - <rect width='100' height='100' fill='red' /> - <rect x='-100' width='100' height='100' fill='red'> - <set attributeName='x' to='0' dur='3s' /> - <set attributeName='fill' to='green' dur='3s' /> - </rect> - <text x='10' y='120'> - There should be a 100x100 green rect at 0,0. - </text> -</svg>
diff --git a/third_party/WebKit/ManualTests/inspector/bp-in-named-eval-after-reload.html b/third_party/WebKit/ManualTests/inspector/bp-in-named-eval-after-reload.html index 4612cd6..723680f 100644 --- a/third_party/WebKit/ManualTests/inspector/bp-in-named-eval-after-reload.html +++ b/third_party/WebKit/ManualTests/inspector/bp-in-named-eval-after-reload.html
@@ -42,14 +42,14 @@ " doNothing();", " console.log(new Date() + ': f1() called');", "}", - "//@sourceURL=f1.js" + "//# sourceURL=f1.js" ].join("\n")); f2 = Function([ "", " doNothing();", " console.log(new Date() + ': f2() called');", - "//@sourceURL=f2.js" + "//# sourceURL=f2.js" ].join("\n")); var button = document.getElementById("button");
diff --git a/third_party/WebKit/ManualTests/inspector/hidden-evals.html b/third_party/WebKit/ManualTests/inspector/hidden-evals.html index c507bcd7..765df0eba 100644 --- a/third_party/WebKit/ManualTests/inspector/hidden-evals.html +++ b/third_party/WebKit/ManualTests/inspector/hidden-evals.html
@@ -1,14 +1,14 @@ <p><b>Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=30212">Bug 30212</a> - Each JS execution in console adds extra item into "scripts" combo</b> -<p>The following manual test creates functions via <tt>eval()</tt> and the -<tt>Function()</tt> constructor, some functions are named using the -<code>//@sourceURL=</code> directive, some aren't. Some contain +<p>The following manual test creates functions via <tt>eval()</tt> and the +<tt>Function()</tt> constructor, some functions are named using the +<code>//# sourceURL=</code> directive, some aren't. Some contain <tt>debugger</tt> commands, some don't. -<p>The functions named <tt>f_named_X</tt> are 'named' via the -<code>//@sourceURL=</code> directive, the ones named <tt>f_unnamed_X</tt> -are not. The 'named' functions should show up in the Scripts select element used +<p>The functions named <tt>f_named_X</tt> are 'named' via the +<code>//# sourceURL=</code> directive, the ones named <tt>f_unnamed_X</tt> +are not. The 'named' functions should show up in the Scripts select element used to select a resource/script to view, the 'unnamed' ones should not. <ul> @@ -25,8 +25,8 @@ <li><p>debugger should stop in the <code>clickHandler</code> function <li><p>at this point, start stepping <b>into</b> the code <li><p>you should be able to step into functions <code>f_unnamed_1()</code> -and <code>f_unnamed_2()</code>. There are no resource/scripts in the -select element that contain these functions, until you actually are paused +and <code>f_unnamed_2()</code>. There are no resource/scripts in the +select element that contain these functions, until you actually are paused in them. At that point, entries for these functions will be in the select element, named: "(program)". After pausing in both functions, there will be two "(program)" entries. @@ -56,7 +56,7 @@ " doNothing();", " return 'named_1';", "}", - "//@sourceURL=f_named_1.eval" + "//# sourceURL=f_named_1.eval" ].join("\n")); eval([ @@ -70,7 +70,7 @@ "", " doNothing();", " return 'named_2';", - "//@sourceURL=f_named_2.eval" + "//# sourceURL=f_named_2.eval" ].join("\n")); f_unnamed_2 = Function([ @@ -84,7 +84,7 @@ " debugger;", " doNothing();", " return 'named_3';", - "//@sourceURL=f_named_3.eval" + "//# sourceURL=f_named_3.eval" ].join("\n")); f_unnamed_3 = Function([ @@ -104,11 +104,11 @@ f_unnamed_1(); f_named_2(); f_unnamed_2(); - + // press "resume" at this point console.log("press resume before calling f_named_3()"); f_named_3(); - + // press "resume" at this point console.log("press resume before calling f_unnamed_3()"); f_unnamed_3();
diff --git a/third_party/WebKit/ManualTests/inspector/named-evals.html b/third_party/WebKit/ManualTests/inspector/named-evals.html index 0c52531..af00aae6 100644 --- a/third_party/WebKit/ManualTests/inspector/named-evals.html +++ b/third_party/WebKit/ManualTests/inspector/named-evals.html
@@ -6,36 +6,36 @@ console.log(message) } -var funcBody = "(){\n" + +var funcBody = "(){\n" + " var thisFunc = arguments.callee;\n" + -" if (!thisFunc.name) thisFunc.displayName = 'f%';\n" + +" if (!thisFunc.name) thisFunc.displayName = 'f%';\n" + " log(thisFunc.name || thisFunc.displayName);\n" + "}"; var funcs = []; var patterns = [ - // proper use of @sourceURL comment - "//@sourceURL=f%.js\nfuncs.push(function" + funcBody + ")", - "//@sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", - " //@sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", - "// @sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", - "//@ sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", - "//@sourceURL =f%.js\nfuncs.push(function f%" + funcBody + ")", - "//@sourceURL= f%.js\nfuncs.push(function f%" + funcBody + ")", - "//@sourceURL=f%.js \nfuncs.push(function f%" + funcBody + ")", - " // @ sourceURL = f%.js \nfuncs.push(function f%" + funcBody + ")", - "//@sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ");\n//@sourceURL=should-not-see\n", - "funcs.push(function f%" + funcBody + ")\n//@sourceURL=f%.js\n", - "funcs.push(function f%" + funcBody + ")\n//@sourceURL=f%.js \n", - "funcs.push(function f%" + funcBody + ")\n//@sourceURL=f%.js", - - // improper or non-existant use of @sourceURL comment + // proper use of #sourceURL comment + "//#sourceURL=f%.js\nfuncs.push(function" + funcBody + ")", + "//#sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", + " //#sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", + "// #sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", + "//# sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", + "//#sourceURL =f%.js\nfuncs.push(function f%" + funcBody + ")", + "//#sourceURL= f%.js\nfuncs.push(function f%" + funcBody + ")", + "//#sourceURL=f%.js \nfuncs.push(function f%" + funcBody + ")", + " // # sourceURL = f%.js \nfuncs.push(function f%" + funcBody + ")", + "//#sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ");\n//#sourceURL=should-not-see\n", + "funcs.push(function f%" + funcBody + ")\n//#sourceURL=f%.js\n", + "funcs.push(function f%" + funcBody + ")\n//#sourceURL=f%.js \n", + "funcs.push(function f%" + funcBody + ")\n//#sourceURL=f%.js", + + // improper or non-existant use of #sourceURL comment "funcs.push(function f%" + funcBody + ")", - "//@sourceurl=f%.js\nfuncs.push(function f%" + funcBody + ")", + "//#sourceurl=f%.js\nfuncs.push(function f%" + funcBody + ")", "//sourceURL=f%.js\nfuncs.push(function f%" + funcBody + ")", - "/*@sourceURL=f%.js*/\nfuncs.push(function f%" + funcBody + ")", + "/*#sourceURL=f%.js*/\nfuncs.push(function f%" + funcBody + ")", "//\nsourceURL='f%.js';\nfuncs.push(function f%" + funcBody + ")", - "//@sourceURL=\nfuncs.push(function" + funcBody + ")", + "//#sourceURL=\nfuncs.push(function" + funcBody + ")", ]; @@ -48,16 +48,16 @@ <body> <p>This page's JavaScript calls functions from named eval()'s. - + <p>Used to test <a href="https://bugs.webkit.org/show_bug.cgi?id=25475">https://bugs.webkit.org/show_bug.cgi?id=25475</a> <p>Load the Web Inspector and look at -the script's panel, and the script list drop-down control. -You should see entries for scripts named +the script's panel, and the script list drop-down control. +You should see entries for scripts named <tt>"(program):f0.js"</tt> through <tt>"(program):f12.js"</tt>. The entries were named -via proper use of the <tt>//@sourceURL</tt> comment. There will also be entries +via proper use of the <tt>//#sourceURL</tt> comment. There will also be entries named <tt>"(program)"</tt> for source that does not properly use, or use at all, -the <tt>//@sourceURL</tt> comment. +the <tt>//#sourceURL</tt> comment. <p>Now, set a breakpoint in the body of the <tt>"f0"</tt> function in the <tt>"(program):f0.js"</tt> script. Then click this button: @@ -66,7 +66,7 @@ <p>When stopped at the breakpoint, the entry for the function in the call stack control should the name of the script, <tt>"(program):f0.js"</tt>, -beside the function name <tt>"f0"</tt>. Note the function name for +beside the function name <tt>"f0"</tt>. Note the function name for <tt>f0</tt> is set with the new <tt>"displayName"</tt> property. </body> </html>
diff --git a/third_party/WebKit/ManualTests/inspector/remember-last-script.html b/third_party/WebKit/ManualTests/inspector/remember-last-script.html index 52e7f020..a971109 100644 --- a/third_party/WebKit/ManualTests/inspector/remember-last-script.html +++ b/third_party/WebKit/ManualTests/inspector/remember-last-script.html
@@ -23,14 +23,14 @@ <ul> <li>open Web Inspector, switch to the <b>Scripts</b> panel, then close Web Inspector </ul> -</ul> +</ul> <script> f1 = Function([ "", " doNothing();", - "//@sourceURL=f1.js" + "//# sourceURL=f1.js" ].join("\n")); function doNothing() { /* allows multi-line functions, easier to debug */ };
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp index 9f5c4b9..817d9ba 100644 --- a/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp +++ b/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp
@@ -173,7 +173,11 @@ return; m_keyframeGroups = adoptPtr(new KeyframeGroupMap); + RefPtr<TimingFunction> zeroOffsetEasing = m_defaultKeyframeEasing; for (const auto& keyframe : normalizedKeyframes(getFrames())) { + if (keyframe->offset() == 0) + zeroOffsetEasing = &keyframe->easing(); + for (const PropertyHandle& property : keyframe->properties()) { if (property.isCSSProperty()) ASSERT_WITH_MESSAGE(!isShorthandProperty(property.cssProperty()), "Web Animations: Encountered shorthand CSS property (%d) in normalized keyframes.", property.cssProperty()); @@ -191,7 +195,7 @@ // Add synthetic keyframes. m_hasSyntheticKeyframes = false; for (const auto& entry : *m_keyframeGroups) { - if (entry.value->addSyntheticKeyframeIfRequired(m_neutralKeyframeEasing)) + if (entry.value->addSyntheticKeyframeIfRequired(zeroOffsetEasing)) m_hasSyntheticKeyframes = true; entry.value->removeRedundantKeyframes(); @@ -261,18 +265,18 @@ ASSERT(m_keyframes.size() >= 2); } -bool KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired(PassRefPtr<TimingFunction> easing) +bool KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired(PassRefPtr<TimingFunction> zeroOffsetEasing) { ASSERT(!m_keyframes.isEmpty()); bool addedSyntheticKeyframe = false; if (m_keyframes.first()->offset() != 0.0) { - m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, easing)); + m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, zeroOffsetEasing)); addedSyntheticKeyframe = true; } if (m_keyframes.last()->offset() != 1.0) { - appendKeyframe(m_keyframes.last()->neutralKeyframe(1, easing)); + appendKeyframe(m_keyframes.last()->neutralKeyframe(1, nullptr)); addedSyntheticKeyframe = true; }
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h b/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h index 3a463c3..b6cff79 100644 --- a/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h +++ b/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h
@@ -63,7 +63,7 @@ private: void removeRedundantKeyframes(); - bool addSyntheticKeyframeIfRequired(PassRefPtr<TimingFunction> neutralKeyframeEasing); + bool addSyntheticKeyframeIfRequired(PassRefPtr<TimingFunction> zeroOffsetEasing); PropertySpecificKeyframeVector m_keyframes; @@ -118,11 +118,11 @@ bool isTransformRelatedEffect() const override; protected: - KeyframeEffectModelBase(PassRefPtr<TimingFunction> neutralKeyframeEasing) + KeyframeEffectModelBase(PassRefPtr<TimingFunction> defaultKeyframeEasing) : m_lastIteration(0) , m_lastFraction(std::numeric_limits<double>::quiet_NaN()) , m_lastIterationDuration(0) - , m_neutralKeyframeEasing(neutralKeyframeEasing) + , m_defaultKeyframeEasing(defaultKeyframeEasing) , m_hasSyntheticKeyframes(false) { } @@ -143,7 +143,7 @@ mutable int m_lastIteration; mutable double m_lastFraction; mutable double m_lastIterationDuration; - RefPtr<TimingFunction> m_neutralKeyframeEasing; + RefPtr<TimingFunction> m_defaultKeyframeEasing; mutable bool m_hasSyntheticKeyframes; @@ -154,14 +154,14 @@ class KeyframeEffectModel final : public KeyframeEffectModelBase { public: using KeyframeVector = Vector<RefPtr<Keyframe>>; - static KeyframeEffectModel<Keyframe>* create(const KeyframeVector& keyframes, PassRefPtr<TimingFunction> neutralKeyframeEasing = nullptr) + static KeyframeEffectModel<Keyframe>* create(const KeyframeVector& keyframes, PassRefPtr<TimingFunction> defaultKeyframeEasing = nullptr) { - return new KeyframeEffectModel(keyframes, neutralKeyframeEasing); + return new KeyframeEffectModel(keyframes, defaultKeyframeEasing); } private: - KeyframeEffectModel(const KeyframeVector& keyframes, PassRefPtr<TimingFunction> neutralKeyframeEasing) - : KeyframeEffectModelBase(neutralKeyframeEasing) + KeyframeEffectModel(const KeyframeVector& keyframes, PassRefPtr<TimingFunction> defaultKeyframeEasing) + : KeyframeEffectModelBase(defaultKeyframeEasing) { m_keyframes.appendVector(keyframes); }
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 4278ae5..0b32d3f 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -40,6 +40,8 @@ 'css/StyleSheet.idl', 'css/StyleSheetList.idl', 'css/WebKitCSSMatrix.idl', + 'css/cssom/KeywordValue.idl', + 'css/cssom/StyleValue.idl', 'dom/ArrayBuffer.idl', 'dom/ArrayBufferView.idl', 'dom/Attr.idl', @@ -1227,6 +1229,10 @@ 'css/StyleSheetContents.h', 'css/StyleSheetList.cpp', 'css/StyleSheetList.h', + 'css/cssom/KeywordValue.cpp', + 'css/cssom/KeywordValue.h', + 'css/cssom/StyleValue.cpp', + 'css/cssom/StyleValue.h', 'css/invalidation/InvalidationSet.cpp', 'css/invalidation/InvalidationSet.h', 'css/invalidation/InvalidationData.cpp', @@ -2631,8 +2637,8 @@ 'events/PageTransitionEvent.h', 'events/PointerEvent.cpp', 'events/PointerEvent.h', - 'events/PointerIdManager.cpp', - 'events/PointerIdManager.h', + 'events/PointerEventFactory.cpp', + 'events/PointerEventFactory.h', 'events/PopStateEvent.cpp', 'events/PopStateEvent.h', 'events/ProgressEvent.cpp', @@ -3842,6 +3848,7 @@ 'editing/VisibleUnitsTest.cpp', 'editing/serializers/StyledMarkupSerializerTest.cpp', 'events/EventPathTest.cpp', + 'events/PointerEventFactoryTest.cpp', 'experiments/ExperimentsTest.cpp', 'fetch/CachingCorrectnessTest.cpp', 'fetch/ClientHintsPreferencesTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp index 35c241c..de14f7a 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp
@@ -300,17 +300,11 @@ CSSPrimitiveValue::~CSSPrimitiveValue() { - cleanup(); -} - -void CSSPrimitiveValue::cleanup() -{ +#if !ENABLE(OILPAN) switch (type()) { case UnitType::Calc: // We must not call deref() when oilpan is enabled because m_value.calc is traced. -#if !ENABLE(OILPAN) m_value.calc->deref(); -#endif break; case UnitType::CalcPercentageWithNumber: case UnitType::CalcPercentageWithLength: @@ -355,6 +349,7 @@ cssTextCache().remove(this); m_hasCachedCSSText = false; } +#endif } double CSSPrimitiveValue::computeSeconds() const
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.h index 6c3a5ee..a5cba2f8 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.h +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.h
@@ -204,8 +204,6 @@ ~CSSPrimitiveValue(); - void cleanup(); - UnitType typeWithCalcResolved() const; double computeDegrees() const;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in index 062ef004..6d4d2133 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.in +++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -94,7 +94,7 @@ font-weight interpolable, inherited, font, type_name=FontWeight, name_for_methods=Weight, converter=convertFontWeight font-feature-settings inherited, font, name_for_methods=FeatureSettings, converter=convertFontFeatureSettings -webkit-font-smoothing inherited, font, type_name=FontSmoothingMode --webkit-locale inherited, custom_value +-webkit-locale inherited, font, custom_value text-orientation inherited, custom_value -webkit-text-orientation inherited, custom_value writing-mode inherited, custom_value
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.in b/third_party/WebKit/Source/core/css/CSSValueKeywords.in index 0020213..79ceda3 100644 --- a/third_party/WebKit/Source/core/css/CSSValueKeywords.in +++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.in
@@ -964,6 +964,7 @@ // all // initial // inherit +revert unset // background-image, etc.
diff --git a/third_party/WebKit/Source/core/css/CSSVariableData.h b/third_party/WebKit/Source/core/css/CSSVariableData.h index 9b35033..2bfe82653 100644 --- a/third_party/WebKit/Source/core/css/CSSVariableData.h +++ b/third_party/WebKit/Source/core/css/CSSVariableData.h
@@ -23,9 +23,9 @@ return adoptRef(new CSSVariableData(range, needsVariableResolution)); } - static PassRefPtr<CSSVariableData> createResolved(const Vector<CSSParserToken>& resolvedTokens) + static PassRefPtr<CSSVariableData> createResolved(const Vector<CSSParserToken>& resolvedTokens, PassRefPtr<CSSVariableData> unresolvedData) { - return adoptRef(new CSSVariableData(resolvedTokens)); + return adoptRef(new CSSVariableData(resolvedTokens, unresolvedData->m_backingString)); } CSSParserTokenRange tokenRange() { return m_tokens; } @@ -40,8 +40,9 @@ // StylePropertySets contain references to CSSCustomPropertyDeclarations, which // point to the unresolved CSSVariableData values that own the backing strings // this will potentially reference. - CSSVariableData(const Vector<CSSParserToken>& resolvedTokens) - : m_tokens(resolvedTokens) + CSSVariableData(const Vector<CSSParserToken>& resolvedTokens, String backingString) + : m_backingString(backingString) + , m_tokens(resolvedTokens) , m_needsVariableResolution(false) { }
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp new file mode 100644 index 0000000..1022150 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
@@ -0,0 +1,79 @@ +#include "config.h" +#include "core/css/cssom/KeywordValue.h" + +#include "wtf/HashMap.h" + +namespace blink { + +namespace { + +using KeywordTable = HashMap<String, KeywordValue::KeywordValueName>; + +KeywordTable createKeywordTable() +{ + KeywordTable table; + table.set(String("initial"), KeywordValue::KeywordValueName::Initial); + table.set(String("inherit"), KeywordValue::KeywordValueName::Inherit); + table.set(String("revert"), KeywordValue::KeywordValueName::Revert); + table.set(String("unset"), KeywordValue::KeywordValueName::Unset); + return table; +} + +KeywordTable& keywordTable() +{ + DEFINE_STATIC_LOCAL(KeywordTable, keywordTable, (createKeywordTable())); + return keywordTable; +} + +} // namespace + +const String& KeywordValue::keywordValue() const +{ + DEFINE_STATIC_LOCAL(const String, InitialStr, ("initial")); + DEFINE_STATIC_LOCAL(const String, InheritStr, ("inherit")); + DEFINE_STATIC_LOCAL(const String, RevertStr, ("revert")); + DEFINE_STATIC_LOCAL(const String, UnsetStr, ("unset")); + + switch (m_keywordValue) { + case Initial: + return InitialStr; + case Inherit: + return InheritStr; + case Revert: + return RevertStr; + case Unset: + return UnsetStr; + default: + ASSERT_NOT_REACHED(); + return emptyString(); + } +} + +const String& KeywordValue::cssString() const +{ + return keywordValue(); +} + +PassRefPtrWillBeRawPtr<CSSValue> KeywordValue::toCSSValue() +{ + switch (m_keywordValue) { + case Initial: + return cssValuePool().createExplicitInitialValue(); + case Inherit: + return cssValuePool().createInheritedValue(); + case Revert: + return cssValuePool().createIdentifierValue(CSSValueID::CSSValueRevert); + case Unset: + return cssValuePool().createUnsetValue(); + default: + ASSERT_NOT_REACHED(); + return nullptr; + } +} + +KeywordValue::KeywordValueName KeywordValue::keywordValueFromString(const String& keyword) +{ + return keywordTable().get(keyword.lower()); +} + +}
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h new file mode 100644 index 0000000..6bdb0a77 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
@@ -0,0 +1,39 @@ +#ifndef KeywordValue_h +#define KeywordValue_h + +#include "core/CoreExport.h" +#include "core/css/cssom/StyleValue.h" + +namespace blink { + +class CORE_EXPORT KeywordValue : public StyleValue { + DEFINE_WRAPPERTYPEINFO(); + +public: + enum KeywordValueName { + Initial, Inherit, Revert, Unset + }; + + static PassRefPtrWillBeRawPtr<KeywordValue> create(const String& keyword) + { + return adoptRefWillBeNoop(new KeywordValue(keyword)); + } + + StyleValueType type() const override { return KeywordValueType; } + + virtual const String& keywordValue() const; + + const String& cssString() const override; + PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() override; + +protected: + KeywordValue(const String& keyword) : m_keywordValue(keywordValueFromString(keyword)) {} + + static KeywordValueName keywordValueFromString(const String& keyword); + + KeywordValueName m_keywordValue; +}; + +} + +#endif
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.idl b/third_party/WebKit/Source/core/css/cssom/KeywordValue.idl new file mode 100644 index 0000000..edcf68c2 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.idl
@@ -0,0 +1,8 @@ +enum StyleValueKeyword {"initial", "inherit", "default", "unset"}; + +[ + Constructor(DOMString keyword), + RuntimeEnabled=CSSTypedOM +] interface KeywordValue : StyleValue { + readonly attribute StyleValueKeyword keywordValue; +};
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValue.cpp b/third_party/WebKit/Source/core/css/cssom/StyleValue.cpp new file mode 100644 index 0000000..8cab731 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/StyleValue.cpp
@@ -0,0 +1,20 @@ +#include "config.h" +#include "core/css/cssom/StyleValue.h" + +#include "bindings/core/v8/ScriptValue.h" + +namespace blink { + +PassRefPtrWillBeRawPtr<StyleValue> StyleValue::create(const CSSValue& val) +{ + // TODO: implement. + return nullptr; +} + +ScriptValue StyleValue::parse(ScriptState* state, const String& property, const String& cssText) +{ + // TODO: implement. + return ScriptValue(); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValue.h b/third_party/WebKit/Source/core/css/cssom/StyleValue.h new file mode 100644 index 0000000..7dc1841 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/StyleValue.h
@@ -0,0 +1,38 @@ +#ifndef StyleValue_h +#define StyleValue_h + +#include "bindings/core/v8/ScriptWrappable.h" +#include "core/CoreExport.h" +#include "core/css/CSSValue.h" +#include "core/css/CSSValuePool.h" + +namespace blink { + +class ScriptState; +class ScriptValue; + +class CORE_EXPORT StyleValue : public RefCountedWillBeGarbageCollectedFinalized<StyleValue>, public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + +public: + enum StyleValueType { + KeywordValueType, SimpleLengthType, CalcLengthType, NumberType + }; + + virtual StyleValueType type() const = 0; + + static PassRefPtrWillBeRawPtr<StyleValue> create(const CSSValue&); + static ScriptValue parse(ScriptState*, const String& property, const String& cssText); + + virtual const String& cssString() const = 0; + virtual PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() = 0; + + DEFINE_INLINE_VIRTUAL_TRACE() { } + +protected: + StyleValue() {} +}; + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValue.idl b/third_party/WebKit/Source/core/css/cssom/StyleValue.idl new file mode 100644 index 0000000..ef6ba78 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/StyleValue.idl
@@ -0,0 +1,8 @@ +[ + RuntimeEnabled=CSSTypedOM, + WillBeGarbageCollected +] interface StyleValue { + readonly attribute DOMString cssString; + // static (StyleValue or sequence<StyleValue>)? parse(DOMString property, DOMString cssText); + [CallWith=ScriptState] static object? parse(DOMString property, DOMString cssText); +};
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index ca793d0..861279b 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -288,22 +288,13 @@ return value->m_unit == CSSParserValue::Operator && value->iValue == '/'; } -static bool isGeneratedImageValue(CSSParserValue* val) +static bool isGeneratedImageValue(CSSValueID id) { - if (val->m_unit != CSSParserValue::Function) - return false; - - CSSValueID id = val->function->id; - return id == CSSValueLinearGradient - || id == CSSValueRadialGradient - || id == CSSValueRepeatingLinearGradient - || id == CSSValueRepeatingRadialGradient - || id == CSSValueWebkitLinearGradient - || id == CSSValueWebkitRadialGradient - || id == CSSValueWebkitRepeatingLinearGradient - || id == CSSValueWebkitRepeatingRadialGradient - || id == CSSValueWebkitGradient - || id == CSSValueWebkitCrossFade; + return id == CSSValueLinearGradient || id == CSSValueRadialGradient + || id == CSSValueRepeatingLinearGradient || id == CSSValueRepeatingRadialGradient + || id == CSSValueWebkitLinearGradient || id == CSSValueWebkitRadialGradient + || id == CSSValueWebkitRepeatingLinearGradient || id == CSSValueWebkitRepeatingRadialGradient + || id == CSSValueWebkitGradient || id == CSSValueWebkitCrossFade; } inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value) @@ -522,23 +513,8 @@ case CSSPropertyListStyleImage: // <uri> | none | inherit case CSSPropertyBorderImageSource: case CSSPropertyWebkitMaskBoxImageSource: - if (id == CSSValueNone) { - parsedValue = cssValuePool().createIdentifierValue(CSSValueNone); + if (parseFillImage(m_valueList, parsedValue)) m_valueList->next(); - } else if (value->m_unit == CSSParserValue::URI) { - parsedValue = createCSSImageValueWithReferrer(value->string, completeURL(value->string)); - m_valueList->next(); - } else if (isGeneratedImageValue(value)) { - if (parseGeneratedImage(m_valueList, parsedValue)) - m_valueList->next(); - else - return false; - } else if (value->m_unit == CSSParserValue::Function && value->function->id == CSSValueWebkitImageSet) { - parsedValue = parseImageSet(m_valueList); - if (!parsedValue) - return false; - m_valueList->next(); - } break; case CSSPropertyBorderTopWidth: //// <border-width> | inherit @@ -1448,7 +1424,7 @@ parsedValue = parseCounterContent(args, true); } else if (val->function->id == CSSValueWebkitImageSet) { parsedValue = parseImageSet(m_valueList); - } else if (isGeneratedImageValue(val)) { + } else if (isGeneratedImageValue(val->function->id)) { if (!parseGeneratedImage(m_valueList, parsedValue)) return nullptr; } @@ -1557,13 +1533,15 @@ return true; } - if (isGeneratedImageValue(valueList->current())) - return parseGeneratedImage(valueList, value); + if (valueList->current()->m_unit == CSSParserValue::Function) { + if (isGeneratedImageValue(valueList->current()->function->id)) + return parseGeneratedImage(valueList, value); - if (valueList->current()->m_unit == CSSParserValue::Function && valueList->current()->function->id == CSSValueWebkitImageSet) { - value = parseImageSet(m_valueList); - if (value) - return true; + if (valueList->current()->function->id == CSSValueWebkitImageSet) { + value = parseImageSet(m_valueList); + if (value) + return true; + } } return false; @@ -3895,18 +3873,20 @@ if (!context.canAdvance() && context.allowImage()) { if (val->m_unit == CSSParserValue::URI) { context.commitImage(createCSSImageValueWithReferrer(val->string, m_context.completeURL(val->string))); - } else if (isGeneratedImageValue(val)) { - RefPtrWillBeRawPtr<CSSValue> value = nullptr; - if (parseGeneratedImage(m_valueList, value)) - context.commitImage(value.release()); - else - return false; - } else if (val->m_unit == CSSParserValue::Function && val->function->id == CSSValueWebkitImageSet) { - RefPtrWillBeRawPtr<CSSValue> value = parseImageSet(m_valueList); - if (value) - context.commitImage(value.release()); - else - return false; + } else if (val->m_unit == CSSParserValue::Function) { + if (isGeneratedImageValue(val->function->id)) { + RefPtrWillBeRawPtr<CSSValue> value = nullptr; + if (parseGeneratedImage(m_valueList, value)) + context.commitImage(value.release()); + else + return false; + } else if (val->function->id == CSSValueWebkitImageSet) { + RefPtrWillBeRawPtr<CSSValue> value = parseImageSet(m_valueList); + if (value) + context.commitImage(value.release()); + else + return false; + } } else if (val->id == CSSValueNone) context.commitImage(cssValuePool().createIdentifierValue(CSSValueNone)); }
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp index e9695df..a522dcc 100644 --- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -21,17 +21,32 @@ namespace blink { -bool CSSVariableResolver::resolveVariableTokensRecursive(CSSParserTokenRange range, - Vector<CSSParserToken>& result) +void CSSVariableResolver::resolveFallback(CSSParserTokenRange range, + Vector<CSSParserToken>& result, CSSVariableResolver::ResolutionState& context) { + if (!range.atEnd()) { + range.consume(); + resolveVariableReferencesFromTokens(range, result, context); + } else { + context.success = false; + } +} + +void CSSVariableResolver::resolveVariableTokensRecursive(CSSParserTokenRange range, + Vector<CSSParserToken>& result, CSSVariableResolver::ResolutionState& context) +{ + Vector<CSSParserToken> trash; range.consumeWhitespace(); ASSERT(range.peek().type() == IdentToken); AtomicString variableName = range.consumeIncludingWhitespace().value(); ASSERT(range.atEnd() || (range.peek().type() == CommaToken)); + // Cycle detection. if (m_variablesSeen.contains(variableName)) { - m_cycleDetected = true; - return false; + context.success = false; + context.cycleStartPoints.add(variableName); + resolveFallback(range, trash, context); + return; } CSSVariableData* variableData = m_styleVariableData ? m_styleVariableData->getVariable(variableName) : nullptr; @@ -39,45 +54,57 @@ Vector<CSSParserToken> tokens; if (variableData->needsVariableResolution()) { m_variablesSeen.add(variableName); - resolveVariableReferencesFromTokens(variableData->tokens(), tokens); + resolveVariableReferencesFromTokens(variableData->tokens(), result, context); m_variablesSeen.remove(variableName); // The old variable data holds onto the backing string the new resolved CSSVariableData // relies on. Ensure it will live beyond us overwriting the RefPtr in StyleVariableData. ASSERT(variableData->refCount() > 1); - m_styleVariableData->setVariable(variableName, CSSVariableData::createResolved(tokens)); + m_styleVariableData->setVariable(variableName, CSSVariableData::createResolved(tokens, variableData)); + if (!context.cycleStartPoints.isEmpty()) { + if (context.cycleStartPoints.contains(variableName)) + context.cycleStartPoints.remove(variableName); + + if (!context.cycleStartPoints.isEmpty()) { + resolveFallback(range, trash, context); + return; + } + } } else { tokens = variableData->tokens(); } + if (!tokens.isEmpty()) { - result.appendVector(tokens); - return true; + // Check that loops are not induced by the fallback. + resolveFallback(range, trash, context); + if (context.cycleStartPoints.isEmpty()) { + // It's OK if the fallback fails to resolve - we're not actually taking it. + context.success = true; + result.appendVector(tokens); + } + return; } } - if (range.atEnd()) - return false; - - // Comma Token, as asserted above. - range.consume(); - - resolveVariableReferencesFromTokens(range, result); - return true; + // We're legitimately falling back, so reset success flag. + context.success = true; + resolveFallback(range, result, context); } -bool CSSVariableResolver::resolveVariableReferencesFromTokens(CSSParserTokenRange range, - Vector<CSSParserToken>& result) +void CSSVariableResolver::resolveVariableReferencesFromTokens(CSSParserTokenRange range, + Vector<CSSParserToken>& result, CSSVariableResolver::ResolutionState& context) { while (!range.atEnd()) { if (range.peek().functionId() != CSSValueVar) { result.append(range.consume()); - } else if (!resolveVariableTokensRecursive(range.consumeBlock(), result) || m_cycleDetected) { - result.clear(); - return false; + } else { + resolveVariableTokensRecursive(range.consumeBlock(), result, context); } } - return true; + if (!context.success) + result.clear(); + return; } void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value) @@ -86,7 +113,9 @@ CSSVariableResolver resolver(state.style()->variables()); Vector<CSSParserToken> tokens; - if (!resolver.resolveVariableReferencesFromTokens(value.variableDataValue()->tokens(), tokens)) + ResolutionState resolutionContext; + resolver.resolveVariableReferencesFromTokens(value.variableDataValue()->tokens(), tokens, resolutionContext); + if (!resolutionContext.success) return; CSSParserContext context(HTMLStandardMode, 0); @@ -111,21 +140,20 @@ Vector<CSSParserToken> resolvedTokens; CSSVariableResolver resolver(variables, variable.key); - resolver.resolveVariableReferencesFromTokens(variable.value->tokens(), resolvedTokens); + ResolutionState context; + resolver.resolveVariableReferencesFromTokens(variable.value->tokens(), resolvedTokens, context); - variable.value = CSSVariableData::createResolved(resolvedTokens); + variable.value = CSSVariableData::createResolved(resolvedTokens, variable.value); } } CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData) : m_styleVariableData(styleVariableData) - , m_cycleDetected(false) { } CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData, AtomicString& variable) : m_styleVariableData(styleVariableData) - , m_cycleDetected(false) { m_variablesSeen.add(variable); }
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h index 6b542fc..cefc755 100644 --- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h +++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h
@@ -27,12 +27,25 @@ CSSVariableResolver(StyleVariableData*); CSSVariableResolver(StyleVariableData*, AtomicString& variable); - bool resolveVariableTokensRecursive(CSSParserTokenRange, Vector<CSSParserToken>& result); - bool resolveVariableReferencesFromTokens(CSSParserTokenRange tokens, Vector<CSSParserToken>& result); + struct ResolutionState { + bool success; + // Resolution doesn't finish when a cycle is detected. Fallbacks still + // need to be tracked for additional cycles, and invalidation only + // applies back to cycle starts. This context member tracks all + // detected cycle start points. + HashSet<AtomicString> cycleStartPoints; + + ResolutionState() + : success(true) + { }; + }; + + void resolveFallback(CSSParserTokenRange, Vector<CSSParserToken>& result, ResolutionState& context); + void resolveVariableTokensRecursive(CSSParserTokenRange, Vector<CSSParserToken>& result, ResolutionState& context); + void resolveVariableReferencesFromTokens(CSSParserTokenRange tokens, Vector<CSSParserToken>& result, ResolutionState& context); StyleVariableData* m_styleVariableData; HashSet<AtomicString> m_variablesSeen; - bool m_cycleDetected; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/FontBuilder.cpp b/third_party/WebKit/Source/core/css/resolver/FontBuilder.cpp index e55f82e..767f762f4 100644 --- a/third_party/WebKit/Source/core/css/resolver/FontBuilder.cpp +++ b/third_party/WebKit/Source/core/css/resolver/FontBuilder.cpp
@@ -32,7 +32,6 @@ #include "core/layout/TextAutosizer.h" #include "platform/FontFamilyNames.h" #include "platform/fonts/FontDescription.h" -#include "platform/text/LocaleToScriptMapping.h" namespace blink { @@ -138,12 +137,11 @@ m_fontDescription.setStretch(fontStretch); } -void FontBuilder::setScript(const AtomicString& locale) +void FontBuilder::setLocale(const AtomicString& locale) { - set(PropertySetFlag::Script); + set(PropertySetFlag::Locale); m_fontDescription.setLocale(locale); - m_fontDescription.setScript(localeToScriptCodeForFontSelection(locale)); } void FontBuilder::setStyle(FontStyle italic) @@ -361,10 +359,8 @@ description.setStretch(m_fontDescription.stretch()); if (isSet(PropertySetFlag::FeatureSettings)) description.setFeatureSettings(m_fontDescription.featureSettings()); - if (isSet(PropertySetFlag::Script)) { - description.setLocale(m_fontDescription.locale()); - description.setScript(m_fontDescription.script()); - } + if (isSet(PropertySetFlag::Locale)) + description.setLocale(m_fontDescription.locale(false)); if (isSet(PropertySetFlag::Style)) description.setStyle(m_fontDescription.style()); if (isSet(PropertySetFlag::Variant)) @@ -393,7 +389,6 @@ { FontDescription fontDescription = FontDescription(); fontDescription.setLocale(documentStyle.locale()); - fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle.locale())); setFamilyDescription(fontDescription, FontBuilder::initialFamilyDescription()); setSize(fontDescription, FontDescription::Size(FontSize::initialKeywordSize(), 0.0f, false));
diff --git a/third_party/WebKit/Source/core/css/resolver/FontBuilder.h b/third_party/WebKit/Source/core/css/resolver/FontBuilder.h index bb07902..3900127 100644 --- a/third_party/WebKit/Source/core/css/resolver/FontBuilder.h +++ b/third_party/WebKit/Source/core/css/resolver/FontBuilder.h
@@ -58,7 +58,7 @@ void setStretch(FontStretch); void setFamilyDescription(const FontDescription::FamilyDescription&); void setFeatureSettings(PassRefPtr<FontFeatureSettings>); - void setScript(const AtomicString& locale); + void setLocale(const AtomicString&); void setStyle(FontStyle); void setVariant(FontVariant); void setVariantLigatures(const FontDescription::VariantLigatures&); @@ -81,6 +81,7 @@ static TextRenderingMode initialTextRendering() { return AutoTextRendering; } static FontVariant initialVariant() { return FontVariantNormal; } static FontDescription::VariantLigatures initialVariantLigatures() { return FontDescription::VariantLigatures(); } + static const AtomicString& initialLocale() { return nullAtom; } static FontStyle initialStyle() { return FontStyleNormal; } static FontDescription::Kerning initialKerning() { return FontDescription::AutoKerning; } static FontSmoothingMode initialFontSmoothing() { return AutoSmoothing; } @@ -109,7 +110,7 @@ Stretch, Family, FeatureSettings, - Script, + Locale, Style, SizeAdjust, Variant,
diff --git a/third_party/WebKit/Source/core/css/resolver/FontBuilderTest.cpp b/third_party/WebKit/Source/core/css/resolver/FontBuilderTest.cpp index f68e4189..291ca14 100644 --- a/third_party/WebKit/Source/core/css/resolver/FontBuilderTest.cpp +++ b/third_party/WebKit/Source/core/css/resolver/FontBuilderTest.cpp
@@ -11,7 +11,6 @@ #include "core/frame/Settings.h" #include "core/style/ComputedStyle.h" #include "core/testing/DummyPageHolder.h" -#include "platform/text/LocaleToScriptMapping.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -141,11 +140,10 @@ static void fontScriptBase(FontDescription& d) { d.setLocale("no"); - d.setScript(localeToScriptCodeForFontSelection("no")); } static void fontScriptValue(FontBuilder& b) { - b.setScript("se"); + b.setLocale("se"); } INSTANTIATE_TEST_CASE_P(AllFields, FontBuilderAdditiveTest,
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp index de1b88a..a7ab238 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -763,11 +763,10 @@ { if (value->isPrimitiveValue()) { ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueAuto); - state.style()->setLocale(nullAtom); + state.fontBuilder().setLocale(nullAtom); } else { - state.style()->setLocale(AtomicString(toCSSStringValue(value)->value())); + state.fontBuilder().setLocale(AtomicString(toCSSStringValue(value)->value())); } - state.fontBuilder().setScript(state.style()->locale()); } void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAppRegion(StyleResolverState&)
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index 4d343cda..57a0fc5 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -529,7 +529,9 @@ RefPtr<ComputedStyle> documentStyle = ComputedStyle::create(); documentStyle->setRTLOrdering(document.visuallyOrdered() ? VisualOrder : LogicalOrder); documentStyle->setZoom(frame && !document.printing() ? frame->pageZoomFactor() : 1); - documentStyle->setLocale(document.contentLanguage()); + FontDescription documentFontDescription = documentStyle->fontDescription(); + documentFontDescription.setLocale(document.contentLanguage()); + documentStyle->setFontDescription(documentFontDescription); documentStyle->setZIndex(0); documentStyle->setUserModify(document.inDesignMode() ? READ_WRITE : READ_ONLY); // These are designed to match the user-agent stylesheet values for the document element
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 5059ce6..b0ec8b3 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -995,7 +995,7 @@ return false; } -IntRect Element::boundsInViewportSpace() +IntRect Element::boundsInViewport() { document().updateLayoutIgnorePendingStylesheets(); @@ -1021,7 +1021,7 @@ for (size_t i = 1; i < quads.size(); ++i) result.unite(quads[i].enclosingBoundingBox()); - return view->soonToBeRemovedContentsToUnscaledViewport(result); + return view->contentsToViewport(result); } ClientRectList* Element::getClientRects()
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h index 701aa3f..5a54f02 100644 --- a/third_party/WebKit/Source/core/dom/Element.h +++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -211,7 +211,7 @@ void scrollTo(double x, double y); virtual void scrollTo(const ScrollToOptions&); - IntRect boundsInViewportSpace(); + IntRect boundsInViewport(); ClientRectList* getClientRects(); ClientRect* getBoundingClientRect();
diff --git a/third_party/WebKit/Source/core/editing/EditingStyle.cpp b/third_party/WebKit/Source/core/editing/EditingStyle.cpp index 3a9cc01..015b29e7 100644 --- a/third_party/WebKit/Source/core/editing/EditingStyle.cpp +++ b/third_party/WebKit/Source/core/editing/EditingStyle.cpp
@@ -557,7 +557,7 @@ return false; CSSValueID unicodeBidiValue = toCSSPrimitiveValue(unicodeBidi.get())->getValueID(); - if (unicodeBidiValue == CSSValueEmbed) { + if (isEmbedOrIsolate(unicodeBidiValue)) { RefPtrWillBeRawPtr<CSSValue> direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection); if (!direction || !direction->isPrimitiveValue()) return false; @@ -649,7 +649,7 @@ { RefPtrWillBeRawPtr<EditingStyle> textDirection = EditingStyle::create(); textDirection->m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode); - textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed, m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi)); + textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueIsolate, m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi)); textDirection->m_mutableStyle->setProperty(CSSPropertyDirection, m_mutableStyle->getPropertyValue(CSSPropertyDirection), m_mutableStyle->propertyIsImportant(CSSPropertyDirection)); @@ -1346,6 +1346,13 @@ return style; } +static bool isUnicodeBidiNestedOrMultipleEmbeddings(CSSValueID valueID) +{ + return valueID == CSSValueEmbed || valueID == CSSValueBidiOverride + || valueID == CSSValueWebkitIsolate || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext + || valueID == CSSValueIsolate || valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext; +} + WritingDirection EditingStyle::textDirectionForSelection(const VisibleSelection& selection, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings) { hasNestedOrMultipleEmbeddings = true; @@ -1375,7 +1382,7 @@ continue; CSSValueID unicodeBidiValue = toCSSPrimitiveValue(unicodeBidi.get())->getValueID(); - if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride) + if (isUnicodeBidiNestedOrMultipleEmbeddings(unicodeBidiValue)) return NaturalWritingDirection; } } @@ -1411,7 +1418,7 @@ if (unicodeBidiValue == CSSValueBidiOverride) return NaturalWritingDirection; - ASSERT(unicodeBidiValue == CSSValueEmbed); + ASSERT(isEmbedOrIsolate(unicodeBidiValue)); RefPtrWillBeRawPtr<CSSValue> direction = style->getPropertyCSSValue(CSSPropertyDirection); if (!direction || !direction->isPrimitiveValue()) continue;
diff --git a/third_party/WebKit/Source/core/editing/EditingStyle.h b/third_party/WebKit/Source/core/editing/EditingStyle.h index 0ddcd752..c98e6bd 100644 --- a/third_party/WebKit/Source/core/editing/EditingStyle.h +++ b/third_party/WebKit/Source/core/editing/EditingStyle.h
@@ -141,6 +141,10 @@ static PassRefPtrWillBeRawPtr<EditingStyle> styleAtSelectionStart(const VisibleSelection&, bool shouldUseBackgroundColorInEffect = false); static WritingDirection textDirectionForSelection(const VisibleSelection&, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings); + static bool isEmbedOrIsolate(CSSValueID unicodeBidi) + { + return unicodeBidi == CSSValueIsolate || unicodeBidi == CSSValueWebkitIsolate || unicodeBidi == CSSValueEmbed; + } DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp index 4b46d35d..b54f6e5 100644 --- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -550,8 +550,10 @@ static HTMLElement* highestEmbeddingAncestor(Node* startNode, Node* enclosingNode) { for (Node* n = startNode; n && n != enclosingNode; n = n->parentNode()) { - if (n->isHTMLElement() && getIdentifierValue(CSSComputedStyleDeclaration::create(n).get(), CSSPropertyUnicodeBidi) == CSSValueEmbed) + if (n->isHTMLElement() + && EditingStyle::isEmbedOrIsolate(getIdentifierValue(CSSComputedStyleDeclaration::create(n).get(), CSSPropertyUnicodeBidi))) { return toHTMLElement(n); + } } return 0;
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp index 29125bd..0a0cb671 100644 --- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -634,7 +634,7 @@ static bool executeMakeTextWritingDirectionLeftToRight(LocalFrame& frame, Event*, EditorCommandSource, const String&) { RefPtrWillBeRawPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(HTMLQuirksMode); - style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed); + style->setProperty(CSSPropertyUnicodeBidi, CSSValueIsolate); style->setProperty(CSSPropertyDirection, CSSValueLtr); frame.editor().applyStyle(style.get(), EditActionSetWritingDirection); return true; @@ -651,7 +651,7 @@ static bool executeMakeTextWritingDirectionRightToLeft(LocalFrame& frame, Event*, EditorCommandSource, const String&) { RefPtrWillBeRawPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(HTMLQuirksMode); - style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed); + style->setProperty(CSSPropertyUnicodeBidi, CSSValueIsolate); style->setProperty(CSSPropertyDirection, CSSValueRtl); frame.editor().applyStyle(style.get(), EditActionSetWritingDirection); return true;
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.cpp b/third_party/WebKit/Source/core/events/PointerEvent.cpp index d8fa922..1202103 100644 --- a/third_party/WebKit/Source/core/events/PointerEvent.cpp +++ b/third_party/WebKit/Source/core/events/PointerEvent.cpp
@@ -10,105 +10,6 @@ namespace blink { -namespace { - -const char* pointerTypeNameForWebPointPointerType(WebPointerProperties::PointerType type) -{ - switch (type) { - case WebPointerProperties::PointerType::Unknown: - return ""; - case WebPointerProperties::PointerType::Touch: - return "touch"; - case WebPointerProperties::PointerType::Pen: - return "pen"; - case WebPointerProperties::PointerType::Mouse: - return "mouse"; - } - ASSERT_NOT_REACHED(); - return ""; -} - -} - -PassRefPtrWillBeRawPtr<PointerEvent> PointerEvent::create(const AtomicString& type, - const bool isPrimary, const PlatformMouseEvent& mouseEvent, - PassRefPtrWillBeRawPtr<Node> relatedTarget, - PassRefPtrWillBeRawPtr<AbstractView> view) -{ - PointerEventInit pointerEventInit; - - // TODO(crbug.com/537319): Define a constant somewhere for mouse id. - pointerEventInit.setPointerId(0); - pointerEventInit.setPointerType( - pointerTypeNameForWebPointPointerType(mouseEvent.pointerProperties().pointerType)); - pointerEventInit.setIsPrimary(true); - - pointerEventInit.setScreenX(mouseEvent.globalPosition().x()); - pointerEventInit.setScreenY(mouseEvent.globalPosition().y()); - pointerEventInit.setClientX(mouseEvent.position().x()); - pointerEventInit.setClientY(mouseEvent.position().y()); - - pointerEventInit.setButton(mouseEvent.button()); - pointerEventInit.setButtons(MouseEvent::platformModifiersToButtons(mouseEvent.modifiers())); - - pointerEventInit.setPressure(mouseEvent.pointerProperties().force); - pointerEventInit.setTiltX(mouseEvent.pointerProperties().tiltX); - pointerEventInit.setTiltY(mouseEvent.pointerProperties().tiltY); - - UIEventWithKeyState::setFromPlatformModifiers(pointerEventInit, mouseEvent.modifiers()); - - pointerEventInit.setBubbles(type != EventTypeNames::pointerenter - && type != EventTypeNames::pointerleave); - pointerEventInit.setCancelable(type != EventTypeNames::pointerenter - && type != EventTypeNames::pointerleave && type != EventTypeNames::pointercancel); - - pointerEventInit.setView(view); - if (relatedTarget) - pointerEventInit.setRelatedTarget(relatedTarget); - - return PointerEvent::create(type, pointerEventInit); -} - -PassRefPtrWillBeRawPtr<PointerEvent> PointerEvent::create(const AtomicString& type, - const bool isPrimary, const PlatformTouchPoint& touchPoint, - PlatformEvent::Modifiers modifiers, - const double width, const double height, - const double clientX, const double clientY) -{ - const unsigned& pointerId = touchPoint.id(); - const PlatformTouchPoint::State pointState = touchPoint.state(); - - bool pointerReleasedOrCancelled = pointState == PlatformTouchPoint::TouchReleased - || pointState == PlatformTouchPoint::TouchCancelled; - - bool isEnterOrLeave = false; - - PointerEventInit pointerEventInit; - pointerEventInit.setPointerId(pointerId); - pointerEventInit.setPointerType( - pointerTypeNameForWebPointPointerType(touchPoint.pointerProperties().pointerType)); - pointerEventInit.setIsPrimary(isPrimary); - - pointerEventInit.setWidth(width); - pointerEventInit.setHeight(height); - pointerEventInit.setPressure(touchPoint.force()); - pointerEventInit.setTiltX(touchPoint.pointerProperties().tiltX); - pointerEventInit.setTiltY(touchPoint.pointerProperties().tiltY); - pointerEventInit.setScreenX(touchPoint.screenPos().x()); - pointerEventInit.setScreenY(touchPoint.screenPos().y()); - pointerEventInit.setClientX(clientX); - pointerEventInit.setClientY(clientY); - pointerEventInit.setButton(0); - pointerEventInit.setButtons(pointerReleasedOrCancelled ? 0 : 1); - - UIEventWithKeyState::setFromPlatformModifiers(pointerEventInit, modifiers); - - pointerEventInit.setBubbles(!isEnterOrLeave); - pointerEventInit.setCancelable(!isEnterOrLeave && pointState != PlatformTouchPoint::TouchCancelled); - - return PointerEvent::create(type, pointerEventInit); -} - PointerEvent::PointerEvent() : m_pointerId(0) , m_width(0)
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.h b/third_party/WebKit/Source/core/events/PointerEvent.h index ca49448..ebbb789 100644 --- a/third_party/WebKit/Source/core/events/PointerEvent.h +++ b/third_party/WebKit/Source/core/events/PointerEvent.h
@@ -25,16 +25,6 @@ return adoptRefWillBeNoop(new PointerEvent(type, initializer)); } - static PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type, - const bool isPrimary, const PlatformMouseEvent&, PassRefPtrWillBeRawPtr<Node> relatedTarget, - PassRefPtrWillBeRawPtr<AbstractView>); - - static PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type, - const bool isPrimary, const PlatformTouchPoint&, - PlatformEvent::Modifiers, - const double width, const double height, - const double clientX, const double clientY); - long pointerId() const { return m_pointerId; } double width() const { return m_width; } double height() const { return m_height; }
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp new file mode 100644 index 0000000..41e7823 --- /dev/null +++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -0,0 +1,202 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/events/PointerEventFactory.h" + +namespace blink { + +namespace { + +inline int toInt(WebPointerProperties::PointerType t) { return static_cast<int>(t); } + +const char* pointerTypeNameForWebPointPointerType(WebPointerProperties::PointerType type) +{ + switch (type) { + case WebPointerProperties::PointerType::Unknown: + return ""; + case WebPointerProperties::PointerType::Touch: + return "touch"; + case WebPointerProperties::PointerType::Pen: + return "pen"; + case WebPointerProperties::PointerType::Mouse: + return "mouse"; + } + ASSERT_NOT_REACHED(); + return ""; +} + +} // namespace + +const PointerEventFactory::MappedId PointerEventFactory::s_invalidId = 0; + +// Mouse id is 1 to behave the same as MS Edge for compatibility reasons. +const PointerEventFactory::MappedId PointerEventFactory::s_mouseId = 1; + + + +void PointerEventFactory::setIdAndType(PointerEventInit &pointerEventInit, + const WebPointerProperties &pointerProperties) +{ + const WebPointerProperties::PointerType pointerType = pointerProperties.pointerType; + MappedId pointerId = add(PointerEventFactory::IncomingId(toInt(pointerType), pointerProperties.id)); + pointerEventInit.setPointerId(pointerId); + pointerEventInit.setPointerType(pointerTypeNameForWebPointPointerType(pointerType)); + pointerEventInit.setIsPrimary(isPrimary(pointerId)); +} + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactory::create(const AtomicString& type, + const PlatformMouseEvent& mouseEvent, + PassRefPtrWillBeRawPtr<Node> relatedTarget, + PassRefPtrWillBeRawPtr<AbstractView> view) +{ + PointerEventInit pointerEventInit; + + setIdAndType(pointerEventInit, mouseEvent.pointerProperties()); + + pointerEventInit.setScreenX(mouseEvent.globalPosition().x()); + pointerEventInit.setScreenY(mouseEvent.globalPosition().y()); + pointerEventInit.setClientX(mouseEvent.position().x()); + pointerEventInit.setClientY(mouseEvent.position().y()); + + pointerEventInit.setButton(mouseEvent.button()); + pointerEventInit.setButtons(MouseEvent::platformModifiersToButtons(mouseEvent.modifiers())); + + UIEventWithKeyState::setFromPlatformModifiers(pointerEventInit, mouseEvent.modifiers()); + + pointerEventInit.setBubbles(type != EventTypeNames::pointerenter + && type != EventTypeNames::pointerleave); + pointerEventInit.setCancelable(type != EventTypeNames::pointerenter + && type != EventTypeNames::pointerleave && type != EventTypeNames::pointercancel); + + pointerEventInit.setView(view); + if (relatedTarget) + pointerEventInit.setRelatedTarget(relatedTarget); + + return PointerEvent::create(type, pointerEventInit); +} + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactory::create(const AtomicString& type, + const PlatformTouchPoint& touchPoint, PlatformEvent::Modifiers modifiers, + const double width, const double height, + const double clientX, const double clientY) +{ + const PlatformTouchPoint::State pointState = touchPoint.state(); + + bool pointerReleasedOrCancelled = pointState == PlatformTouchPoint::TouchReleased + || pointState == PlatformTouchPoint::TouchCancelled; + + bool isEnterOrLeave = false; + + PointerEventInit pointerEventInit; + + setIdAndType(pointerEventInit, touchPoint.pointerProperties()); + + pointerEventInit.setWidth(width); + pointerEventInit.setHeight(height); + pointerEventInit.setPressure(touchPoint.force()); + pointerEventInit.setTiltX(touchPoint.pointerProperties().tiltX); + pointerEventInit.setTiltY(touchPoint.pointerProperties().tiltY); + pointerEventInit.setScreenX(touchPoint.screenPos().x()); + pointerEventInit.setScreenY(touchPoint.screenPos().y()); + pointerEventInit.setClientX(clientX); + pointerEventInit.setClientY(clientY); + pointerEventInit.setButton(0); + pointerEventInit.setButtons(pointerReleasedOrCancelled ? 0 : 1); + + UIEventWithKeyState::setFromPlatformModifiers(pointerEventInit, modifiers); + + pointerEventInit.setBubbles(!isEnterOrLeave); + pointerEventInit.setCancelable(!isEnterOrLeave && pointState != PlatformTouchPoint::TouchCancelled); + + return PointerEvent::create(type, pointerEventInit); +} + + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactory::createPointerCancel(const PlatformTouchPoint& touchPoint) +{ + PointerEventInit pointerEventInit; + + setIdAndType(pointerEventInit, touchPoint.pointerProperties()); + + pointerEventInit.setBubbles(true); + pointerEventInit.setCancelable(false); + + return PointerEvent::create(EventTypeNames::pointercancel, pointerEventInit); +} + +PointerEventFactory::PointerEventFactory() +{ + clear(); +} + +PointerEventFactory::~PointerEventFactory() +{ + clear(); +} + +void PointerEventFactory::clear() +{ + for (int type = 0; type <= toInt(WebPointerProperties::PointerType::LastEntry); type++) { + m_primaryId[type] = PointerEventFactory::s_invalidId; + m_idCount[type] = 0; + } + m_idMapping.clear(); + m_idReverseMapping.clear(); + + // Always add mouse pointer in initialization and never remove it. + // No need to add it to m_idMapping as it is not going to be used with the existing APIs + m_primaryId[toInt(WebPointerProperties::PointerType::Mouse)] = s_mouseId; + m_idReverseMapping.add(s_mouseId, IncomingId(toInt(WebPointerProperties::PointerType::Mouse), 0)); + + m_currentId = PointerEventFactory::s_mouseId+1; +} + +PointerEventFactory::MappedId PointerEventFactory::add(const IncomingId p) +{ + // Do not add extra mouse pointer as it was added in initialization + if (p.first == toInt(WebPointerProperties::PointerType::Mouse)) + return s_mouseId; + + int type = p.first; + if (m_idMapping.contains(p)) + return m_idMapping.get(p); + // We do not handle the overflow of m_currentId as it should be very rare + MappedId mappedId = m_currentId++; + if (!m_idCount[type]) + m_primaryId[type] = mappedId; + m_idCount[type]++; + m_idMapping.add(p, mappedId); + m_idReverseMapping.add(mappedId, p); + return static_cast<PointerEventFactory::MappedId>(mappedId); +} + +void PointerEventFactory::remove(const PassRefPtrWillBeRawPtr<PointerEvent> pointerEvent) +{ + MappedId mappedId = pointerEvent->pointerId(); + // Do not remove mouse pointer id as it should always be there + if (mappedId == s_mouseId || !m_idReverseMapping.contains(mappedId)) + return; + + IncomingId p = m_idReverseMapping.get(mappedId); + int type = p.first; + m_idReverseMapping.remove(mappedId); + m_idMapping.remove(p); + if (m_primaryId[type] == mappedId) + m_primaryId[type] = PointerEventFactory::s_invalidId; + m_idCount[type]--; +} + +bool PointerEventFactory::isPrimary(PointerEventFactory::MappedId mappedId) const +{ + if (!m_idReverseMapping.contains(mappedId)) + return false; + + IncomingId p = m_idReverseMapping.get(mappedId); + int type = p.first; + return m_primaryId[type] == mappedId; +} + + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.h b/third_party/WebKit/Source/core/events/PointerEventFactory.h new file mode 100644 index 0000000..605340b --- /dev/null +++ b/third_party/WebKit/Source/core/events/PointerEventFactory.h
@@ -0,0 +1,73 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PointerEventFactory_h +#define PointerEventFactory_h + +#include "core/CoreExport.h" +#include "core/events/PointerEvent.h" +#include "public/platform/WebPointerProperties.h" +#include "wtf/Allocator.h" +#include "wtf/HashMap.h" + +namespace blink { + +/** + Helper class for tracking the pointer ids for each type of PointerEvents. + Using id re-mapping at this layer, this class makes sure that regardless of the + domain of the id (i.e. in touch or pen) the corresponding pointer event will have + a unique id amongst all pointer events as per pointer events' specification. + This class intended to behave the same as existing browsers as much as possible + for compatibility reasons. Particularly it behaves very similar to MS Edge to have + pointer event ids generated by mouse always equal 1 and those that are generated + by touch and pen will have increasing ids from 2. +*/ +class CORE_EXPORT PointerEventFactory { + DISALLOW_NEW(); +public: + + PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type, + const PlatformMouseEvent&, PassRefPtrWillBeRawPtr<Node> relatedTarget, + PassRefPtrWillBeRawPtr<AbstractView>); + + PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type, + const PlatformTouchPoint&, PlatformEvent::Modifiers, + const double width, const double height, + const double clientX, const double clientY); + + PassRefPtrWillBeRawPtr<PointerEvent> createPointerCancel(const PlatformTouchPoint&); + + PointerEventFactory(); + ~PointerEventFactory(); + + // Clear all the existing ids. + void clear(); + /* + * When a pointerEvent with a particular id is removed that id is considered + * free even though there might have been other PointerEvents that were + * generated with the same id before. + */ + void remove(const PassRefPtrWillBeRawPtr<PointerEvent>); + +private: + typedef long MappedId; + typedef std::pair<int, int> IncomingId; + + MappedId add(const IncomingId); + bool isPrimary(const MappedId) const; + void setIdAndType(PointerEventInit &, const WebPointerProperties &); + + static const MappedId s_invalidId; + static const MappedId s_mouseId; + + PointerEventFactory::MappedId m_currentId; + HashMap<IncomingId, MappedId, WTF::PairHash<int, int>, WTF::PairHashTraits<WTF::UnsignedWithZeroKeyHashTraits<int>, WTF::UnsignedWithZeroKeyHashTraits<int>>> m_idMapping; + HashMap<MappedId, IncomingId, WTF::IntHash<MappedId>, WTF::UnsignedWithZeroKeyHashTraits<MappedId>> m_idReverseMapping; + MappedId m_primaryId[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1]; + MappedId m_idCount[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1]; +}; + +} // namespace blink + +#endif // PointerEventFactory_h
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp new file mode 100644 index 0000000..0271541 --- /dev/null +++ b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
@@ -0,0 +1,238 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "core/events/PointerEventFactory.h" + +#include "core/frame/FrameView.h" +#include "core/page/Page.h" +#include "public/platform/WebPointerProperties.h" +#include <climits> +#include <gtest/gtest.h> + +namespace blink { + +class PointerEventFactoryTest : public ::testing::Test { +protected: + void SetUp() override; + PassRefPtrWillBeRawPtr<PointerEvent> createAndCheckTouchCancel( + WebPointerProperties::PointerType, int rawId, + int uniqueId, bool isPrimary); + PassRefPtrWillBeRawPtr<PointerEvent> createAndCheckTouchEvent( + WebPointerProperties::PointerType, int rawId, + int uniqueId, bool isPrimary); + PassRefPtrWillBeRawPtr<PointerEvent> createAndCheckMouseEvent( + WebPointerProperties::PointerType, int rawId, + int uniqueId, bool isPrimary); + + PointerEventFactory m_pointerEventFactory; + unsigned m_expectedMouseId; + unsigned m_mappedIdStart; + + class PlatformTouchPointBuilder : public PlatformTouchPoint { + public: + PlatformTouchPointBuilder(WebPointerProperties::PointerType, int); + }; + + class PlatformMouseEventBuilder : public PlatformMouseEvent { + public: + PlatformMouseEventBuilder(WebPointerProperties::PointerType, int); + }; +}; + +void PointerEventFactoryTest::SetUp() +{ + m_expectedMouseId = 1; + m_mappedIdStart = 2; + +} + +PointerEventFactoryTest::PlatformTouchPointBuilder::PlatformTouchPointBuilder( + WebPointerProperties::PointerType pointerType, int id) +{ + m_pointerProperties.id = id; + m_pointerProperties.pointerType = pointerType; +} + +PointerEventFactoryTest::PlatformMouseEventBuilder::PlatformMouseEventBuilder( + WebPointerProperties::PointerType pointerType, int id) +{ + m_pointerProperties.pointerType = pointerType; + m_pointerProperties.id = id; +} + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactoryTest::createAndCheckTouchCancel( + WebPointerProperties::PointerType pointerType, int rawId, + int uniqueId, bool isPrimary) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.createPointerCancel( + PointerEventFactoryTest::PlatformTouchPointBuilder(pointerType, rawId)); + EXPECT_EQ(uniqueId, pointerEvent->pointerId()); + EXPECT_EQ(isPrimary, pointerEvent->isPrimary()); + return pointerEvent; +} + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactoryTest::createAndCheckTouchEvent( + WebPointerProperties::PointerType pointerType, int rawId, + int uniqueId, bool isPrimary) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.create( + EventTypeNames::pointerdown, PointerEventFactoryTest::PlatformTouchPointBuilder(pointerType, rawId), PlatformEvent::NoModifiers, 0, 0, 0, 0); + EXPECT_EQ(uniqueId, pointerEvent->pointerId()); + EXPECT_EQ(isPrimary, pointerEvent->isPrimary()); + return pointerEvent; +} + +PassRefPtrWillBeRawPtr<PointerEvent> PointerEventFactoryTest::createAndCheckMouseEvent( + WebPointerProperties::PointerType pointerType, int rawId, int uniqueId, bool isPrimary) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.create( + EventTypeNames::pointerenter, PlatformMouseEventBuilder(pointerType, rawId), nullptr, nullptr); + EXPECT_EQ(uniqueId, pointerEvent->pointerId()); + EXPECT_EQ(isPrimary, pointerEvent->isPrimary()); + return pointerEvent; +} + +TEST_F(PointerEventFactoryTest, MousePointer) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent2 = createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); + + m_pointerEventFactory.remove(pointerEvent1); + + createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); + + m_pointerEventFactory.remove(pointerEvent1); + m_pointerEventFactory.remove(pointerEvent2); + + createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 1, m_expectedMouseId, true); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 20, m_expectedMouseId, true); +} + +TEST_F(PointerEventFactoryTest, TouchPointerPrimaryRemovedWhileAnotherIsThere) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 1, m_mappedIdStart+1, false); + + m_pointerEventFactory.remove(pointerEvent1); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 2, m_mappedIdStart+2, false); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 1, m_mappedIdStart+1, false); +} + +TEST_F(PointerEventFactoryTest, TouchPointerReleasedAndPressedAgain) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent2 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 1, m_mappedIdStart+1, false); + + m_pointerEventFactory.remove(pointerEvent1); + m_pointerEventFactory.remove(pointerEvent2); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 1, m_mappedIdStart+2, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+3, false); + + m_pointerEventFactory.clear(); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 10, m_mappedIdStart, true); +} + +TEST_F(PointerEventFactoryTest, TouchAndDrag) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent2 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + + m_pointerEventFactory.remove(pointerEvent1); + m_pointerEventFactory.remove(pointerEvent2); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+1, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+1, true); + + // Remove an obsolete (i.e. already removed) pointer event which should have no effect + m_pointerEventFactory.remove(pointerEvent1); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+1, true); + createAndCheckTouchCancel(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+1, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart+1, true); +} + +TEST_F(PointerEventFactoryTest, MouseAndTouchAndPen) +{ + createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, true); + + RefPtrWillBeRawPtr<PointerEvent> pointerEvent2 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 1, m_mappedIdStart+2, false); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent3 = createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 2, m_mappedIdStart+3, false); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 47213, m_mappedIdStart+4, false); + + m_pointerEventFactory.remove(pointerEvent1); + m_pointerEventFactory.remove(pointerEvent2); + m_pointerEventFactory.remove(pointerEvent3); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 100, m_mappedIdStart+5, true); + + m_pointerEventFactory.clear(); + + createAndCheckMouseEvent(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Touch, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, true); +} + +TEST_F(PointerEventFactoryTest, PenAsTouchAndMouseEvent) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart, true); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart+1, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 2, m_mappedIdStart+2, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart, true); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart+1, false); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart+1, false); + + m_pointerEventFactory.remove(pointerEvent1); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+3, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+3, false); + createAndCheckTouchCancel(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+3, false); + + m_pointerEventFactory.clear(); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart, true); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, false); + createAndCheckTouchCancel(WebPointerProperties::PointerType::Pen, 1, m_mappedIdStart, true); + createAndCheckTouchCancel(WebPointerProperties::PointerType::Pen, 0, m_mappedIdStart+1, false); +} + + +TEST_F(PointerEventFactoryTest, OutOfRange) +{ + RefPtrWillBeRawPtr<PointerEvent> pointerEvent1 = createAndCheckMouseEvent(WebPointerProperties::PointerType::Unknown, 0, m_mappedIdStart, true); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Unknown, 1, m_mappedIdStart+1, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Unknown, 2, m_mappedIdStart+2, false); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Unknown, 0, m_mappedIdStart, true); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Unknown, 3, m_mappedIdStart+3, false); + createAndCheckMouseEvent(WebPointerProperties::PointerType::Unknown, 2, m_mappedIdStart+2, false); + createAndCheckTouchCancel(WebPointerProperties::PointerType::Unknown, 3, m_mappedIdStart+3, false); + + m_pointerEventFactory.remove(pointerEvent1); + + createAndCheckTouchEvent(WebPointerProperties::PointerType::Unknown, 0, m_mappedIdStart+4, false); + createAndCheckTouchEvent(WebPointerProperties::PointerType::Unknown, INT_MAX, m_mappedIdStart+5, false); + + m_pointerEventFactory.clear(); + + for (int i = 0; i < 100; ++i) { + createAndCheckMouseEvent(WebPointerProperties::PointerType::Touch, i, m_mappedIdStart+i, i == 0); + } + + for (int i = 0; i < 100; ++i) { + createAndCheckTouchEvent(WebPointerProperties::PointerType::Mouse, i, m_expectedMouseId, true); + } + createAndCheckTouchCancel(WebPointerProperties::PointerType::Mouse, 0, m_expectedMouseId, true); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/events/PointerIdManager.cpp b/third_party/WebKit/Source/core/events/PointerIdManager.cpp deleted file mode 100644 index a0342b72..0000000 --- a/third_party/WebKit/Source/core/events/PointerIdManager.cpp +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "config.h" -#include "core/events/PointerIdManager.h" - -namespace blink { - -namespace { - -inline int toInt(WebPointerProperties::PointerType t) { return static_cast<int>(t); } - -} // namespace - -PointerIdManager::PointerIdManager() -{ - clear(); -} - -PointerIdManager::~PointerIdManager() -{ - clear(); -} - -void PointerIdManager::clear() -{ - for (int type = 0; type <= toInt(WebPointerProperties::PointerType::LastEntry); type++) { - m_ids[type].clear(); - m_hasPrimaryId[type] = false; - } -} - -void PointerIdManager::add(WebPointerProperties::PointerType type, unsigned id) -{ - if (m_ids[toInt(type)].isEmpty()) - m_hasPrimaryId[toInt(type)] = true; - m_ids[toInt(type)].add(id); -} - -void PointerIdManager::remove(WebPointerProperties::PointerType type, unsigned id) -{ - if (isPrimary(type, id)) { - m_ids[toInt(type)].removeFirst(); - m_hasPrimaryId[toInt(type)] = false; - } else { - // Note that simply counting the number of ids instead of storing all of them is not enough. - // When id is absent, remove() should be a no-op. - m_ids[toInt(type)].remove(id); - } -} - -bool PointerIdManager::isPrimary(WebPointerProperties::PointerType type, unsigned id) -{ - return m_hasPrimaryId[toInt(type)] && m_ids[toInt(type)].first() == id; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/events/PointerIdManager.h b/third_party/WebKit/Source/core/events/PointerIdManager.h deleted file mode 100644 index b3e0134..0000000 --- a/third_party/WebKit/Source/core/events/PointerIdManager.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PointerIdManager_h -#define PointerIdManager_h - -#include "public/platform/WebPointerProperties.h" -#include "wtf/Allocator.h" -#include "wtf/ListHashSet.h" - -namespace blink { - -/** - Helper class for tracking the primary pointer id for each type of PointerEvents. -*/ -class PointerIdManager { - DISALLOW_NEW(); -public: - PointerIdManager(); - ~PointerIdManager(); - void clear(); - void add(WebPointerProperties::PointerType, unsigned); - void remove(WebPointerProperties::PointerType, unsigned); - bool isPrimary(WebPointerProperties::PointerType, unsigned); - -private: - // TODO(crbug.com/537319): Switch to /one/ set of ids to guarantee uniqueness. - ListHashSet<unsigned> m_ids[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1]; - bool m_hasPrimaryId[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1]; -}; - -} // namespace blink - -#endif // PointerIdManager_h
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp index 26a7e67..5f8f096 100644 --- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
@@ -176,13 +176,6 @@ ContainerNode::setActive(down); } -void HTMLAnchorElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == hrefAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "a", hrefAttr.toString(), oldValue, newValue); - HTMLElement::attributeChanged(name, oldValue, newValue, reason); -} - void HTMLAnchorElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == hrefAttr) { @@ -206,6 +199,7 @@ } } invalidateCachedVisitedLinkHash(); + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "a", hrefAttr.toString(), oldValue, value); } else if (name == nameAttr || name == titleAttr) { // Do nothing. } else if (name == relAttr) {
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.h b/third_party/WebKit/Source/core/html/HTMLAnchorElement.h index 25fecb3..e489810 100644 --- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.h +++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.h
@@ -90,7 +90,6 @@ protected: HTMLAnchorElement(const QualifiedName&, Document&); - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; bool supportsFocus() const override;
diff --git a/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp b/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp index 0ee295be..0d81d0e 100644 --- a/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLButtonElement.cpp
@@ -103,6 +103,8 @@ m_type = SUBMIT; setNeedsWillValidateCheck(); } else { + if (name == formactionAttr) + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "button", formactionAttr.toString(), oldValue, value); HTMLFormControlElement::parseAttribute(name, oldValue, value); } } @@ -218,11 +220,4 @@ return request; } -void HTMLButtonElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == formactionAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "button", formactionAttr.toString(), oldValue, newValue); - HTMLFormControlElement::attributeChanged(name, oldValue, newValue, reason); -} - } // namespace
diff --git a/third_party/WebKit/Source/core/html/HTMLButtonElement.h b/third_party/WebKit/Source/core/html/HTMLButtonElement.h index ef9cee6f..ffc3df0 100644 --- a/third_party/WebKit/Source/core/html/HTMLButtonElement.h +++ b/third_party/WebKit/Source/core/html/HTMLButtonElement.h
@@ -52,7 +52,6 @@ bool alwaysCreateUserAgentShadowRoot() const override { return false; } Node::InsertionNotificationRequest insertedInto(ContainerNode*) override; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; bool isPresentationAttribute(const QualifiedName&) const override; void defaultEventHandler(Event*) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index 217f79b..3b5b5c4 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -561,11 +561,9 @@ RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback); - if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == DefaultMimeType)) { - asyncCreatorRef->scheduleAsyncBlobCreation(true); - } else { - asyncCreatorRef->scheduleAsyncBlobCreation(false, quality); - } + + // TODO(xlai): Remove idle-periods version of implementation completely, http://crbug.com/564218 + asyncCreatorRef->scheduleAsyncBlobCreation(false, quality); } SecurityOrigin* HTMLCanvasElement::securityOrigin() const
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp index 42a3af0e..e54d4128 100644 --- a/third_party/WebKit/Source/core/html/HTMLElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -234,7 +234,7 @@ else addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, "ltr"); if (!hasTagName(bdiTag) && !hasTagName(bdoTag) && !hasTagName(outputTag)) - addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, CSSValueEmbed); + addPropertyToPresentationAttributeStyle(style, CSSPropertyUnicodeBidi, CSSValueIsolate); } } else if (name.matches(XMLNames::langAttr)) { mapLanguageAttributeToLocale(value, style);
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp index cd7c635b..7847d89 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
@@ -49,13 +49,10 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form) : LabelableElement(tagName, document) - , m_disabled(false) - , m_isAutofilled(false) - , m_isReadOnly(false) - , m_isRequired(false) - , m_hasValidationMessage(false) , m_ancestorDisabledState(AncestorDisabledStateUnknown) , m_dataListAncestorState(Unknown) + , m_isAutofilled(false) + , m_hasValidationMessage(false) , m_willValidateInitialized(false) , m_willValidate(true) , m_isValid(true) @@ -163,14 +160,10 @@ formAttributeChanged(); UseCounter::count(document(), UseCounter::FormAttribute); } else if (name == disabledAttr) { - bool oldDisabled = m_disabled; - m_disabled = !value.isNull(); - if (oldDisabled != m_disabled) + if (oldValue.isNull() != value.isNull()) disabledAttributeChanged(); } else if (name == readonlyAttr) { - bool wasReadOnly = m_isReadOnly; - m_isReadOnly = !value.isNull(); - if (wasReadOnly != m_isReadOnly) { + if (oldValue.isNull() != value.isNull()) { setNeedsWillValidateCheck(); pseudoStateChanged(CSSSelector::PseudoReadOnly); pseudoStateChanged(CSSSelector::PseudoReadWrite); @@ -178,9 +171,7 @@ LayoutTheme::theme().controlStateChanged(*layoutObject(), ReadOnlyControlState); } } else if (name == requiredAttr) { - bool wasRequired = m_isRequired; - m_isRequired = !value.isNull(); - if (wasRequired != m_isRequired) + if (oldValue.isNull() != value.isNull()) requiredAttributeChanged(); UseCounter::count(document(), UseCounter::RequiredAttribute); } else if (name == autofocusAttr) { @@ -212,6 +203,16 @@ pseudoStateChanged(CSSSelector::PseudoOptional); } +bool HTMLFormControlElement::isReadOnly() const +{ + return fastHasAttribute(HTMLNames::readonlyAttr); +} + +bool HTMLFormControlElement::isDisabledOrReadOnly() const +{ + return isDisabledFormControl() || isReadOnly(); +} + bool HTMLFormControlElement::supportsAutofocus() const { return false; @@ -356,7 +357,7 @@ bool HTMLFormControlElement::isDisabledFormControl() const { - if (m_disabled) + if (fastHasAttribute(disabledAttr)) return true; if (m_ancestorDisabledState == AncestorDisabledStateUnknown) @@ -366,7 +367,7 @@ bool HTMLFormControlElement::isRequired() const { - return m_isRequired; + return fastHasAttribute(requiredAttr); } String HTMLFormControlElement::resultForDialogSubmit()
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.h b/third_party/WebKit/Source/core/html/HTMLFormControlElement.h index 1809c8a..aa34278 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.h +++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.h
@@ -100,8 +100,8 @@ void setCustomValidity(const String&) final; void findCustomValidationMessageTextDirection(const String& message, TextDirection &messageDir, String& subMessage, TextDirection& subMessageDir); - bool isReadOnly() const { return m_isReadOnly; } - bool isDisabledOrReadOnly() const { return isDisabledFormControl() || m_isReadOnly; } + bool isReadOnly() const; + bool isDisabledOrReadOnly() const; bool isAutofocusable() const; @@ -174,17 +174,13 @@ // Requests validity recalc for all ancestor fieldsets, if exist. void fieldSetAncestorsSetNeedsValidityCheck(Node*); - bool m_disabled : 1; - bool m_isAutofilled : 1; - bool m_isReadOnly : 1; - bool m_isRequired : 1; - bool m_hasValidationMessage : 1; - enum AncestorDisabledState { AncestorDisabledStateUnknown, AncestorDisabledStateEnabled, AncestorDisabledStateDisabled }; mutable AncestorDisabledState m_ancestorDisabledState; enum DataListAncestorState { Unknown, InsideDataList, NotInsideDataList }; mutable enum DataListAncestorState m_dataListAncestorState; + bool m_isAutofilled : 1; + bool m_hasValidationMessage : 1; // The initial value of m_willValidate depends on the derived class. We can't // initialize it with a virtual function in the constructor. m_willValidate // is not deterministic as long as m_willValidateInitialized is false.
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp index 284ea311..ee77275db 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -508,6 +508,7 @@ KURL actionURL = document().completeURL(m_attributes.action().isEmpty() ? document().url().string() : m_attributes.action()); if (MixedContentChecker::isMixedFormAction(document().frame(), actionURL)) UseCounter::count(document().frame(), UseCounter::MixedContentFormPresent); + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "form", actionAttr.toString(), oldValue, value); } else if (name == targetAttr) { m_attributes.setTarget(value); } else if (name == methodAttr) { @@ -525,13 +526,6 @@ } } -void HTMLFormElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == actionAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "form", actionAttr.toString(), oldValue, newValue); - HTMLElement::attributeChanged(name, oldValue, newValue, reason); -} - void HTMLFormElement::associate(FormAssociatedElement& e) { m_associatedElementsAreDirty = true;
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.h b/third_party/WebKit/Source/core/html/HTMLFormElement.h index afacd30..9bb909cb 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormElement.h +++ b/third_party/WebKit/Source/core/html/HTMLFormElement.h
@@ -128,7 +128,6 @@ void handleLocalEvents(Event&) override; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; bool isURLAttribute(const Attribute&) const override; bool hasLegalLinkAttribute(const QualifiedName&) const override;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp index 7b431d4..b88f3f2 100644 --- a/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp
@@ -111,7 +111,7 @@ { if (name == srcdocAttr) { if (!value.isNull()) { - setLocation("about:srcdoc"); + setLocation(srcdocURL().string()); } else { const AtomicString& srcValue = fastGetAttribute(srcAttr); if (!srcValue.isNull())
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp index 7cc02a1..4ccd90eec 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -92,13 +92,6 @@ } } -void HTMLIFrameElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == srcAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "iframe", srcAttr.toString(), oldValue, newValue); - HTMLFrameElementBase::attributeChanged(name, oldValue, newValue, reason); -} - void HTMLIFrameElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == nameAttr) { @@ -116,6 +109,8 @@ if (!value.isNull()) SecurityPolicy::referrerPolicyFromString(value, &m_referrerPolicy); } else { + if (name == srcAttr) + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "iframe", srcAttr.toString(), oldValue, value); HTMLFrameElementBase::parseAttribute(name, oldValue, value); } }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h index e6fba67d3..3c52fda 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -42,7 +42,6 @@ explicit HTMLIFrameElement(Document&); void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; bool isPresentationAttribute(const QualifiedName&) const override; void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp index d42aea57..b2ee9ac 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -666,13 +666,6 @@ } } -void HTMLInputElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == formactionAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "input", formactionAttr.toString(), oldValue, newValue); - HTMLTextFormControlElement::attributeChanged(name, oldValue, newValue, reason); -} - void HTMLInputElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { ASSERT(m_inputType); @@ -782,6 +775,8 @@ HTMLTextFormControlElement::parseAttribute(name, oldValue, value); UseCounter::count(document(), UseCounter::PrefixedDirectoryAttribute); } else { + if (name == formactionAttr) + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "input", formactionAttr.toString(), oldValue, value); HTMLTextFormControlElement::parseAttribute(name, oldValue, value); } m_inputTypeView->attributeChanged();
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.h b/third_party/WebKit/Source/core/html/HTMLInputElement.h index a47325bd..8fa7673 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.h +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.h
@@ -302,7 +302,6 @@ void accessKeyAction(bool sendMouseEvents) final; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; bool isPresentationAttribute(const QualifiedName&) const final; void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) final;
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp index 670b5fc..52932b1 100644 --- a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
@@ -235,16 +235,6 @@ scope.addLabel(newForAttributeValue, this); } -void HTMLLabelElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == HTMLNames::forAttr) { - TreeScope& scope = treeScope(); - if (scope.shouldCacheLabelsByForAttribute()) - updateLabel(scope, oldValue, newValue); - } - HTMLElement::attributeChanged(name, oldValue, newValue, reason); -} - Node::InsertionNotificationRequest HTMLLabelElement::insertedInto(ContainerNode* insertionPoint) { InsertionNotificationRequest result = HTMLElement::insertedInto(insertionPoint); @@ -286,6 +276,11 @@ formAttributeChanged(); UseCounter::count(document(), UseCounter::HTMLLabelElementFormContentAttribute); } else { + if (attributeName == forAttr) { + TreeScope& scope = treeScope(); + if (scope.shouldCacheLabelsByForAttribute()) + updateLabel(scope, oldValue, attributeValue); + } HTMLElement::parseAttribute(attributeName, oldValue, attributeValue); } }
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.h b/third_party/WebKit/Source/core/html/HTMLLabelElement.h index 7fd73f3..fcdf958 100644 --- a/third_party/WebKit/Source/core/html/HTMLLabelElement.h +++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.h
@@ -57,7 +57,6 @@ bool isInteractiveContent() const override; void accessKeyAction(bool sendMouseEvents) override; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; InsertionNotificationRequest insertedInto(ContainerNode*) override; void removedFrom(ContainerNode*) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp index 5d99724..7d27e7c 100644 --- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -167,6 +167,8 @@ m_relAttribute = LinkRelAttribute(value); process(); } else if (name == hrefAttr) { + // Log href attribute before logging resource fetching in process(). + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "link", hrefAttr.toString(), oldValue, value); process(); } else if (name == typeAttr) { m_type = value; @@ -454,13 +456,6 @@ DOMSettableTokenListObserver::trace(visitor); } -void HTMLLinkElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == hrefAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "link", hrefAttr.toString(), oldValue, newValue); - HTMLElement::attributeChanged(name, oldValue, newValue, reason); -} - PassOwnPtrWillBeRawPtr<LinkStyle> LinkStyle::create(HTMLLinkElement* owner) { return adoptPtrWillBeNoop(new LinkStyle(owner));
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.h b/third_party/WebKit/Source/core/html/HTMLLinkElement.h index f499d54..42d102b5 100644 --- a/third_party/WebKit/Source/core/html/HTMLLinkElement.h +++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.h
@@ -184,9 +184,6 @@ private: HTMLLinkElement(Document&, bool createdByParser); - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; - void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; - LinkStyle* linkStyle() const; LinkImport* linkImport() const; LinkResource* linkResourceToProcess(); @@ -195,6 +192,7 @@ static void processCallback(Node*); // From Node and subclassses + void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; InsertionNotificationRequest insertedInto(ContainerNode*) override; void removedFrom(ContainerNode*) override; bool isURLAttribute(const Attribute&) const override;
diff --git a/third_party/WebKit/Source/core/html/HTMLMetaElement-in.cpp b/third_party/WebKit/Source/core/html/HTMLMetaElement-in.cpp index bd080732..94e2597b 100644 --- a/third_party/WebKit/Source/core/html/HTMLMetaElement-in.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMetaElement-in.cpp
@@ -29,6 +29,7 @@ #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" #include "core/html/HTMLHeadElement.h" +#include "core/html/parser/HTMLParserIdioms.h" #include "core/inspector/ConsoleMessage.h" #include "core/loader/FrameLoaderClient.h" #include "core/loader/HttpEquiv.h" @@ -492,6 +493,14 @@ HttpEquiv::process(document(), httpEquivValue, contentValue, inDocumentHead(this)); } +WTF::TextEncoding HTMLMetaElement::computeEncoding() const +{ + HTMLAttributeList attributeList; + for (const Attribute& attr : attributes()) + attributeList.append(std::make_pair(attr.name().localName(), attr.value().string())); + return encodingFromMetaAttributes(attributeList); +} + const AtomicString& HTMLMetaElement::content() const { return getAttribute(contentAttr);
diff --git a/third_party/WebKit/Source/core/html/HTMLMetaElement.h b/third_party/WebKit/Source/core/html/HTMLMetaElement.h index b887cb38..b82ae3b 100644 --- a/third_party/WebKit/Source/core/html/HTMLMetaElement.h +++ b/third_party/WebKit/Source/core/html/HTMLMetaElement.h
@@ -26,6 +26,7 @@ #include "core/CoreExport.h" #include "core/dom/ViewportDescription.h" #include "core/html/HTMLElement.h" +#include "wtf/text/TextEncoding.h" namespace blink { @@ -44,6 +45,10 @@ static void getViewportDescriptionFromContentAttribute(const String& content, ViewportDescription&, Document*, bool viewportMetaZeroValuesQuirk); + // Encoding computed from processing the http-equiv, charset and content + // attributes. + WTF::TextEncoding computeEncoding() const; + const AtomicString& content() const; const AtomicString& httpEquiv() const; const AtomicString& name() const;
diff --git a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp index b10b52a..3284714 100644 --- a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
@@ -79,19 +79,14 @@ void HTMLScriptElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { - if (name == srcAttr) + if (name == srcAttr) { m_loader->handleSourceAttribute(value); - else if (name == asyncAttr) + logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "script", srcAttr.toString(), oldValue, value); + } else if (name == asyncAttr) { m_loader->handleAsyncAttribute(); - else + } else { HTMLElement::parseAttribute(name, oldValue, value); -} - -void HTMLScriptElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason) -{ - if (name == srcAttr) - logEventIfIsolatedWorldAndInDocument("blinkSetAttribute", "script", srcAttr.toString(), oldValue, newValue); - HTMLElement::attributeChanged(name, oldValue, newValue, reason); + } } Node::InsertionNotificationRequest HTMLScriptElement::insertedInto(ContainerNode* insertionPoint)
diff --git a/third_party/WebKit/Source/core/html/HTMLScriptElement.h b/third_party/WebKit/Source/core/html/HTMLScriptElement.h index 4168c932..75d1177 100644 --- a/third_party/WebKit/Source/core/html/HTMLScriptElement.h +++ b/third_party/WebKit/Source/core/html/HTMLScriptElement.h
@@ -52,7 +52,6 @@ HTMLScriptElement(Document&, bool wasInsertedByParser, bool alreadyStarted); void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override; - void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override; InsertionNotificationRequest insertedInto(ContainerNode*) override; void didNotifySubtreeInsertionsToDocument() override; void childrenChanged(const ChildrenChange&) override;
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index 898e7d5..c955bc52 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -374,7 +374,7 @@ m_lastGestureScrollOverWidget = false; m_scrollbarHandlingScrollGesture = nullptr; m_touchPressed = false; - m_pointerIdManager.clear(); + m_pointerEventFactory.clear(); m_preventMouseEventForPointerTypeMouse = false; m_inPointerCanceledState = false; m_mouseDownMayStartDrag = false; @@ -1618,7 +1618,7 @@ if (!RuntimeEnabledFeatures::pointerEventEnabled()) return false; - RefPtrWillBeRawPtr<PointerEvent> pointerEvent = PointerEvent::create(eventType, true, + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.create(eventType, mouseEvent, relatedTarget, m_frame->document()->domWindow()); target->dispatchEvent(pointerEvent.get()); return pointerEvent->defaultPrevented() || pointerEvent->defaultHandled(); @@ -2923,10 +2923,8 @@ int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0; locationInRootFrame = view->contentsToRootFrame(IntPoint(x, y)); } else if (focusedElement) { - IntRect clippedRect = focusedElement->boundsInViewportSpace(); - // FIXME: boundsInViewportSpace is actually in the weird scaled but untranslated coordinate space of - // the old-style visual viewport. crbug.com/459591. - locationInRootFrame = flooredIntPoint(visualViewport.viewportCSSPixelsToRootFrame(clippedRect.center())); + IntRect clippedRect = focusedElement->boundsInViewport(); + locationInRootFrame = visualViewport.viewportToRootFrame(clippedRect.center()); } else { locationInRootFrame = IntPoint( rightAligned @@ -3654,22 +3652,17 @@ for (unsigned i = 0; i < touchInfos.size(); ++i) { TouchInfo& touchInfo = touchInfos[i]; const PlatformTouchPoint& touchPoint = touchInfo.point; - const unsigned& pointerId = touchPoint.id(); const PlatformTouchPoint::State pointState = touchPoint.state(); + if (pointState == PlatformTouchPoint::TouchStationary || !touchInfo.knownTarget) continue; bool pointerReleasedOrCancelled = pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled; - const WebPointerProperties::PointerType pointerType = touchPoint.pointerProperties().pointerType; - if (pointState == PlatformTouchPoint::TouchPressed) - m_pointerIdManager.add(pointerType, pointerId); - - RefPtrWillBeRawPtr<PointerEvent> pointerEvent = PointerEvent::create( + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.create( pointerEventNameForTouchPointState(pointState), - m_pointerIdManager.isPrimary(pointerType, pointerId), touchPoint, event.modifiers(), touchInfo.adjustedRadius.width(), touchInfo.adjustedRadius.height(), touchInfo.adjustedPagePoint.x(), touchInfo.adjustedPagePoint.y()); @@ -3679,7 +3672,7 @@ // Remove the released/cancelled id at the end to correctly determine primary id above. if (pointerReleasedOrCancelled) - m_pointerIdManager.remove(pointerType, pointerId); + m_pointerEventFactory.remove(pointerEvent); } } @@ -3691,23 +3684,16 @@ for (unsigned i = 0; i < touchInfos.size(); ++i) { TouchInfo& touchInfo = touchInfos[i]; const PlatformTouchPoint& point = touchInfo.point; - const unsigned& pointerId = point.id(); const PlatformTouchPoint::State pointState = point.state(); if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) continue; - PointerEventInit pointerEventInit; - pointerEventInit.setPointerId(pointerId); - pointerEventInit.setBubbles(true); - pointerEventInit.setCancelable(false); - - RefPtrWillBeRawPtr<PointerEvent> pointerEvent = PointerEvent::create( - EventTypeNames::pointercancel, pointerEventInit); + RefPtrWillBeRawPtr<PointerEvent> pointerEvent = m_pointerEventFactory.createPointerCancel(point); touchInfo.touchTarget->dispatchEvent(pointerEvent.get()); - m_pointerIdManager.remove(WebPointerProperties::PointerType::Touch, pointerId); + m_pointerEventFactory.remove(pointerEvent); } }
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h index 20aee78..cb16f500 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.h +++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -27,7 +27,7 @@ #define EventHandler_h #include "core/CoreExport.h" -#include "core/events/PointerIdManager.h" +#include "core/events/PointerEventFactory.h" #include "core/events/TextEventInputType.h" #include "core/layout/HitTestRequest.h" #include "core/page/DragActions.h" @@ -423,7 +423,7 @@ bool m_touchPressed; - PointerIdManager m_pointerIdManager; + PointerEventFactory m_pointerEventFactory; // Prevents firing mousedown, mousemove & mouseup in-between a canceled pointerdown and next pointerup/pointercancel. // See "PREVENT MOUSE EVENT flag" in the spec:
diff --git a/third_party/WebKit/Source/core/inspector/ContentSearchUtils.cpp b/third_party/WebKit/Source/core/inspector/ContentSearchUtils.cpp index 24d0fe1..a568cb22 100644 --- a/third_party/WebKit/Source/core/inspector/ContentSearchUtils.cpp +++ b/third_party/WebKit/Source/core/inspector/ContentSearchUtils.cpp
@@ -107,11 +107,9 @@ return result; } -static String findMagicComment(const String& content, const String& name, MagicCommentType commentType, bool* deprecated = 0) +static String findMagicComment(const String& content, const String& name, MagicCommentType commentType) { ASSERT(name.find("=") == kNotFound); - if (deprecated) - *deprecated = false; unsigned length = content.length(); unsigned nameLength = name.length(); @@ -133,7 +131,7 @@ if ((content[pos + 1] != '/' || commentType != JavaScriptMagicComment) && (content[pos + 1] != '*' || commentType != CSSMagicComment)) continue; - if (content[pos + 2] != '#' && content[pos + 2] != '@') + if (content[pos + 2] != '#') continue; if (content[pos + 3] != ' ' && content[pos + 3] != '\t') continue; @@ -149,9 +147,6 @@ break; } - if (deprecated && content[pos + 2] == '@') - *deprecated = true; - ASSERT(equalSignPos); ASSERT(commentType != CSSMagicComment || closingCommentPos); size_t urlPos = equalSignPos + 1; @@ -173,14 +168,14 @@ return match; } -String findSourceURL(const String& content, MagicCommentType commentType, bool* deprecated) +String findSourceURL(const String& content, MagicCommentType commentType) { - return findMagicComment(content, "sourceURL", commentType, deprecated); + return findMagicComment(content, "sourceURL", commentType); } -String findSourceMapURL(const String& content, MagicCommentType commentType, bool* deprecated) +String findSourceMapURL(const String& content, MagicCommentType commentType) { - return findMagicComment(content, "sourceMappingURL", commentType, deprecated); + return findMagicComment(content, "sourceMappingURL", commentType); } } // namespace ContentSearchUtils
diff --git a/third_party/WebKit/Source/core/inspector/ContentSearchUtils.h b/third_party/WebKit/Source/core/inspector/ContentSearchUtils.h index 00d21f37..0859004a 100644 --- a/third_party/WebKit/Source/core/inspector/ContentSearchUtils.h +++ b/third_party/WebKit/Source/core/inspector/ContentSearchUtils.h
@@ -48,8 +48,8 @@ PassOwnPtr<ScriptRegexp> createSearchRegex(const String& query, bool caseSensitive, bool isRegex); PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::SearchMatch>> searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex); -String findSourceURL(const String& content, MagicCommentType, bool* deprecated = nullptr); -String findSourceMapURL(const String& content, MagicCommentType, bool* deprecated = nullptr); +String findSourceURL(const String& content, MagicCommentType); +String findSourceMapURL(const String& content, MagicCommentType); } // namespace ContentSearchUtils } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp b/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp index cc8485a..32bbc417 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp
@@ -1408,10 +1408,8 @@ String styleSheetText; bool success = getText(&styleSheetText); if (success) { - bool deprecated; - String commentValue = ContentSearchUtils::findSourceURL(styleSheetText, ContentSearchUtils::CSSMagicComment, &deprecated); + String commentValue = ContentSearchUtils::findSourceURL(styleSheetText, ContentSearchUtils::CSSMagicComment); if (!commentValue.isEmpty()) { - // FIXME: add deprecated console message here. m_sourceURL = commentValue; return commentValue; } @@ -1461,12 +1459,9 @@ String styleSheetText; bool success = getText(&styleSheetText); if (success) { - bool deprecated; - String commentValue = ContentSearchUtils::findSourceMapURL(styleSheetText, ContentSearchUtils::CSSMagicComment, &deprecated); - if (!commentValue.isEmpty()) { - // FIXME: add deprecated console message here. + String commentValue = ContentSearchUtils::findSourceMapURL(styleSheetText, ContentSearchUtils::CSSMagicComment); + if (!commentValue.isEmpty()) return commentValue; - } } return m_pageStyleSheet->contents()->sourceMapURL(); }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp index f9cad8bd..2dd2562 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -407,6 +407,17 @@ value->setString("frame", toHexString(frame)); value->setString("url", request.url().string()); value->setString("requestMethod", request.httpMethod()); + const char* priority = 0; + switch (request.priority()) { + case ResourceLoadPriorityVeryLow: priority = "VeryLow"; break; + case ResourceLoadPriorityLow: priority = "Low"; break; + case ResourceLoadPriorityMedium: priority = "Medium"; break; + case ResourceLoadPriorityHigh: priority = "High"; break; + case ResourceLoadPriorityVeryHigh: priority = "VeryHigh"; break; + case ResourceLoadPriorityUnresolved: break; + } + if (priority) + value->setString("priority", priority); setCallStack(value.get()); return value.release(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp index 39e158b..7fbda64d 100644 --- a/third_party/WebKit/Source/core/layout/LayoutView.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -48,10 +48,34 @@ #include "platform/geometry/FloatQuad.h" #include "platform/geometry/TransformState.h" #include "platform/graphics/paint/PaintController.h" +#include "public/platform/Platform.h" #include <inttypes.h> namespace blink { +namespace { + +class HitTestLatencyRecorder { +public: + HitTestLatencyRecorder(bool allowsChildFrameContent) + : m_start(WTF::monotonicallyIncreasingTime()) + , m_allowsChildFrameContent(allowsChildFrameContent) + { + } + + ~HitTestLatencyRecorder() + { + int duration = static_cast<int>((WTF::monotonicallyIncreasingTime() - m_start) * 1000000); + Platform::current()->histogramCustomCounts(m_allowsChildFrameContent ? "Event.Latency.HitTestRecursive" : "Event.Latency.HitTest", duration, 0, 10000000, 100); + } + +private: + double m_start; + bool m_allowsChildFrameContent; +}; + +} // namespace + LayoutView::LayoutView(Document* document) : LayoutBlockFlow(document) , m_frameView(document->view()) @@ -91,6 +115,7 @@ // Note that Document::updateLayout calls its parent's updateLayout. DocumentLifecycle::PreventThrottlingScope preventThrottling(document().lifecycle()); frameView()->updateLifecycleToCompositingCleanPlusScrolling(); + HitTestLatencyRecorder hitTestLatencyRecorder(result.hitTestRequest().allowsChildFrameContent()); return hitTestNoLifecycleUpdate(result); }
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp index d0c6f21..3f7b65e1 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp +++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1455,7 +1455,7 @@ bool FrameLoader::shouldTreatURLAsSrcdocDocument(const KURL& url) const { - if (!equalIgnoringCase(url.string(), "about:srcdoc")) + if (!url.isAboutSrcdocURL()) return false; HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); if (!isHTMLIFrameElement(ownerElement))
diff --git a/third_party/WebKit/Source/core/page/PageSerializer.cpp b/third_party/WebKit/Source/core/page/PageSerializer.cpp index e0e53a8..20956a9 100644 --- a/third_party/WebKit/Source/core/page/PageSerializer.cpp +++ b/third_party/WebKit/Source/core/page/PageSerializer.cpp
@@ -58,7 +58,6 @@ #include "core/html/HTMLMetaElement.h" #include "core/html/HTMLStyleElement.h" #include "core/html/ImageDocument.h" -#include "core/html/parser/HTMLParserIdioms.h" #include "core/page/Page.h" #include "core/style/StyleFetchedImage.h" #include "core/style/StyleImage.h" @@ -72,25 +71,13 @@ namespace blink { -bool isCharsetSpecifyingNode(const Node& node) -{ - if (!isHTMLMetaElement(node)) - return false; - - const HTMLMetaElement& element = toHTMLMetaElement(node); - HTMLAttributeList attributeList; - AttributeCollection attributes = element.attributes(); - for (const Attribute& attr: attributes) { - // FIXME: We should deal appropriately with the attribute if they have a namespace. - attributeList.append(std::make_pair(attr.name().localName(), attr.value().string())); - } - WTF::TextEncoding textEncoding = encodingFromMetaAttributes(attributeList); - return textEncoding.isValid(); -} - static bool shouldIgnoreElement(const Element& element) { - return isHTMLScriptElement(element) || isHTMLNoScriptElement(element) || isCharsetSpecifyingNode(element); + if (isHTMLScriptElement(element)) + return true; + if (isHTMLNoScriptElement(element)) + return true; + return isHTMLMetaElement(element) && toHTMLMetaElement(element).computeEncoding().isValid(); } static const QualifiedName& frameOwnerURLAttributeName(const HTMLFrameOwnerElement& frameOwner)
diff --git a/third_party/WebKit/Source/core/page/PageSerializer.h b/third_party/WebKit/Source/core/page/PageSerializer.h index 3ea21ea4..441f893 100644 --- a/third_party/WebKit/Source/core/page/PageSerializer.h +++ b/third_party/WebKit/Source/core/page/PageSerializer.h
@@ -118,10 +118,6 @@ OwnPtr<Delegate> m_delegate; }; -// TODO(lukasza): Stop exposing this implementation detail once the serializers -// are merged. -CORE_EXPORT bool isCharsetSpecifyingNode(const Node&); - } // namespace blink #endif // PageSerializer_h
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index 5c51e0e..f82d8cb 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -531,7 +531,6 @@ || rareInheritedData->hyphenationLimitAfter != other.rareInheritedData->hyphenationLimitAfter || rareInheritedData->hyphenationString != other.rareInheritedData->hyphenationString || rareInheritedData->m_respectImageOrientation != other.rareInheritedData->m_respectImageOrientation - || rareInheritedData->locale != other.rareInheritedData->locale || rareInheritedData->m_rubyPosition != other.rareInheritedData->m_rubyPosition || rareInheritedData->textEmphasisMark != other.rareInheritedData->textEmphasisMark || rareInheritedData->textEmphasisPosition != other.rareInheritedData->textEmphasisPosition
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index 1eacbe1..43ca7e6 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -833,7 +833,7 @@ LineBreak lineBreak() const { return static_cast<LineBreak>(rareInheritedData->lineBreak); } const AtomicString& highlight() const { return rareInheritedData->highlight; } const AtomicString& hyphenationString() const { return rareInheritedData->hyphenationString; } - const AtomicString& locale() const { return rareInheritedData->locale; } + const AtomicString& locale() const { return fontDescription().locale(false); } EResize resize() const { return static_cast<EResize>(rareNonInheritedData->m_resize); } bool hasInlinePaginationAxis() const { @@ -1364,7 +1364,6 @@ void setLineBreak(LineBreak b) { SET_VAR(rareInheritedData, lineBreak, b); } void setHighlight(const AtomicString& h) { SET_VAR(rareInheritedData, highlight, h); } void setHyphenationString(const AtomicString& h) { SET_VAR(rareInheritedData, hyphenationString, h); } - void setLocale(const AtomicString& locale) { SET_VAR(rareInheritedData, locale, locale); } void setResize(EResize r) { SET_VAR(rareNonInheritedData, m_resize, r); } void setColumnWidth(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, f); } void setHasAutoColumnWidth() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, 0); } @@ -1706,7 +1705,6 @@ static const AtomicString& initialHighlight() { return nullAtom; } static ESpeak initialSpeak() { return SpeakNormal; } static const AtomicString& initialHyphenationString() { return nullAtom; } - static const AtomicString& initialLocale() { return nullAtom; } static EResize initialResize() { return RESIZE_NONE; } static ControlPart initialAppearance() { return NoControlPart; } static Order initialRTLOrdering() { return LogicalOrder; }
diff --git a/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp index 1c1622c..f1ef7500 100644 --- a/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp +++ b/third_party/WebKit/Source/core/style/StyleRareInheritedData.cpp
@@ -39,7 +39,7 @@ float firstFloat; Color colors[5]; void* ownPtrs[1]; - AtomicString atomicStrings[4]; + AtomicString atomicStrings[3]; #if ENABLE(OILPAN) void* refPtrs[1]; Persistent<void*> persistentHandles[2]; @@ -155,7 +155,6 @@ , hyphenationLimitBefore(o.hyphenationLimitBefore) , hyphenationLimitAfter(o.hyphenationLimitAfter) , hyphenationLimitLines(o.hyphenationLimitLines) - , locale(o.locale) , textEmphasisCustomMark(o.textEmphasisCustomMark) , tapHighlightColor(o.tapHighlightColor) , appliedTextDecorations(o.appliedTextDecorations) @@ -216,7 +215,6 @@ && m_selfOrAncestorHasDirAutoAttribute == o.m_selfOrAncestorHasDirAutoAttribute && m_respectImageOrientation == o.m_respectImageOrientation && hyphenationString == o.hyphenationString - && locale == o.locale && textEmphasisCustomMark == o.textEmphasisCustomMark && quotesDataEquivalent(o) && m_tabSize == o.m_tabSize
diff --git a/third_party/WebKit/Source/core/style/StyleRareInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareInheritedData.h index 260cd1cb..4b63722 100644 --- a/third_party/WebKit/Source/core/style/StyleRareInheritedData.h +++ b/third_party/WebKit/Source/core/style/StyleRareInheritedData.h
@@ -150,8 +150,6 @@ short hyphenationLimitAfter; short hyphenationLimitLines; - AtomicString locale; - AtomicString textEmphasisCustomMark; RefPtr<QuotesData> quotes;
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp index 0c6e546..ef4671f 100644 --- a/third_party/WebKit/Source/core/testing/Internals.cpp +++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2408,12 +2408,6 @@ return CanvasFontCache::maxFonts(); } -ClientRect* Internals::boundsInViewportSpace(Element* element) -{ - ASSERT(element); - return ClientRect::create(element->boundsInViewportSpace()); -} - void Internals::setScrollChain( ScrollState* scrollState, const WillBeHeapVector<RefPtrWillBeMember<Element>>& elements, ExceptionState&) {
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h index 8fc662a..cab82d14 100644 --- a/third_party/WebKit/Source/core/testing/Internals.h +++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -349,8 +349,6 @@ void setNetworkStateNotifierTestOnly(bool); void setNetworkConnectionInfo(const String&, double downlinkMaxMbps, ExceptionState&); - ClientRect* boundsInViewportSpace(Element*); - unsigned countHitRegions(CanvasRenderingContext*); bool isInCanvasFontCache(Document*, const String&);
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl index bdacffa..953ec941 100644 --- a/third_party/WebKit/Source/core/testing/Internals.idl +++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -319,8 +319,6 @@ boolean isInCanvasFontCache(Document document, DOMString fontString); unsigned long canvasFontCacheMaxFonts(); - ClientRect boundsInViewportSpace(Element element); - DictionaryTest dictionaryTest(); UnionTypesTest unionTypesTest(); [RaisesException] void setScrollChain(ScrollState scrollState, Element[] elements);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js index 7ae65317..dd8eedb 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -70,11 +70,10 @@ /** @type !Array<!WebInspector.ElementsSidebarViewWrapperPane> */ this._elementsSidebarViewWrappers = []; this._currentToolbarPane = null; - this._toolbarPaneElement = createElementWithClass("div", "styles-sidebar-toolbar-pane"); var sharedSidebarModel = new WebInspector.SharedSidebarModel(); this.sidebarPanes.platformFonts = WebInspector.PlatformFontsWidget.createSidebarWrapper(sharedSidebarModel); - this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(this._toolbarPaneElement); + this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(); this.sidebarPanes.computedStyle = WebInspector.ComputedStyleWidget.createSidebarWrapper(this.sidebarPanes.styles, sharedSidebarModel); this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane(); @@ -82,6 +81,8 @@ this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this); this.sidebarPanes.eventListeners = WebInspector.EventListenersWidget.createSidebarWrapper(); + this._stylesSidebarToolbar = this._createStylesSidebarToolbar(this.sidebarPanes.styles); + WebInspector.moduleSetting("sidebarPosition").addChangeListener(this._updateSidebarPosition.bind(this)); this._updateSidebarPosition(); this._loadSidebarViews(); @@ -100,6 +101,26 @@ WebInspector.ElementsPanel.prototype = { /** + * @param {!WebInspector.StylesSidebarPane} ssp + * @return {!Element} + */ + _createStylesSidebarToolbar: function(ssp) + { + var container = createElementWithClass("div", "styles-sidebar-pane-toolbar-container"); + var hbox = container.createChild("div", "hbox styles-sidebar-pane-toolbar"); + var filterContainerElement = hbox.createChild("div", "styles-sidebar-pane-filter-box"); + var filterInput = WebInspector.StylesSidebarPane.createPropertyFilterElement(WebInspector.UIString("Filter"), hbox, ssp.onFilterChanged.bind(ssp)); + filterContainerElement.appendChild(filterInput); + var toolbar = new WebInspector.ExtensibleToolbar("styles-sidebarpane-toolbar", hbox); + toolbar.appendToolbarItem(WebInspector.StylesSidebarPane.createAddNewRuleButton(ssp)); + toolbar.element.classList.add("styles-pane-toolbar", "toolbar-gray-toggled"); + var toolbarPaneContainer = container.createChild("div", "styles-sidebar-toolbar-pane-container"); + this._toolbarPaneElement = createElementWithClass("div", "styles-sidebar-toolbar-pane"); + toolbarPaneContainer.appendChild(this._toolbarPaneElement); + return container; + }, + + /** * @param {?WebInspector.Widget} widget */ showToolbarPane: function(widget) @@ -893,16 +914,16 @@ _updateSidebarPosition: function() { - var vertically; + var horizontally; var position = WebInspector.moduleSetting("sidebarPosition").get(); if (position === "right") - vertically = false; + horizontally = false; else if (position === "bottom") - vertically = true; + horizontally = true; else - vertically = WebInspector.inspectorView.element.offsetWidth < 680; + horizontally = WebInspector.inspectorView.element.offsetWidth < 680; - if (this.sidebarPaneView && vertically === !this._splitWidget.isVertical()) + if (this.sidebarPaneView && horizontally === !this._splitWidget.isVertical()) return; if (this.sidebarPaneView && this.sidebarPaneView.shouldHideOnDetach()) @@ -916,16 +937,18 @@ this._splitWidget.uninstallResizer(this.sidebarPaneView.headerElement()); } - this._splitWidget.setVertical(!vertically); + this._splitWidget.setVertical(!horizontally); var computedPane = new WebInspector.SidebarPane(WebInspector.UIString("Computed")); computedPane.element.classList.add("composite"); computedPane.element.classList.add("fill"); - computedPane.element.classList.add("metrics-and-computed"); + var matchedStylesContainer = new WebInspector.VBox(); + matchedStylesContainer.element.appendChild(this._stylesSidebarToolbar); var matchedStylePanesWrapper = new WebInspector.VBox(); matchedStylePanesWrapper.element.classList.add("style-panes-wrapper"); + matchedStylePanesWrapper.show(matchedStylesContainer.element); var computedStylePanesWrapper = new WebInspector.VBox(); computedStylePanesWrapper.element.classList.add("style-panes-wrapper"); @@ -961,7 +984,7 @@ this._popoverHelper = new WebInspector.PopoverHelper(this.sidebarPaneView.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this)); this._popoverHelper.setTimeout(0); - if (vertically) { + if (horizontally) { this._splitWidget.installResizer(this.sidebarPaneView.headerElement()); var compositePane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title()); @@ -971,7 +994,7 @@ var splitWidget = new WebInspector.SplitWidget(true, true, "stylesPaneSplitViewState", 215); splitWidget.show(compositePane.element); - splitWidget.setMainWidget(matchedStylePanesWrapper); + splitWidget.setMainWidget(matchedStylesContainer); splitWidget.setSidebarWidget(computedStylePanesWrapper); computedPane.show(computedStylePanesWrapper.element); @@ -980,18 +1003,17 @@ var stylesPane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title()); stylesPane.element.classList.add("composite", "fill", "metrics-and-styles"); - matchedStylePanesWrapper.show(stylesPane.element); + matchedStylesContainer.show(stylesPane.element); computedStylePanesWrapper.show(computedPane.element); this.sidebarPaneView.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, tabSelected, this); - this.sidebarPaneView.addPane(stylesPane); this.sidebarPaneView.addPane(computedPane); } this.sidebarPanes.styles.show(matchedStylePanesWrapper.element); this.sidebarPanes.computedStyle.show(computedStylePanesWrapper.element); - showMetrics.call(this, vertically); + showMetrics.call(this, horizontally); this.sidebarPanes.platformFonts.show(computedStylePanesWrapper.element); this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js index 193bc76..a394990 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -30,9 +30,8 @@ /** * @constructor * @extends {WebInspector.ElementsSidebarPane} - * @param {!Element} toolbarPaneElement */ -WebInspector.StylesSidebarPane = function(toolbarPaneElement) +WebInspector.StylesSidebarPane = function() { WebInspector.ElementsSidebarPane.call(this, WebInspector.UIString("Styles")); this.setMinimumSize(96, 26); @@ -40,23 +39,8 @@ WebInspector.moduleSetting("colorFormat").addChangeListener(this.update.bind(this)); WebInspector.moduleSetting("textEditorIndent").addChangeListener(this.update.bind(this)); - var hbox = this.element.createChild("div", "hbox styles-sidebar-pane-toolbar"); - var filterContainerElement = hbox.createChild("div", "styles-sidebar-pane-filter-box"); - this._filterInput = WebInspector.StylesSidebarPane.createPropertyFilterElement(WebInspector.UIString("Filter"), hbox, this._onFilterChanged.bind(this)); - filterContainerElement.appendChild(this._filterInput); - - var toolbar = new WebInspector.ExtensibleToolbar("styles-sidebarpane-toolbar", hbox); - toolbar.appendToolbarItem(WebInspector.StylesSidebarPane.createAddNewRuleButton(this)); - - toolbar.element.classList.add("styles-pane-toolbar", "toolbar-gray-toggled"); - - var toolbarPaneContainer = this.element.createChild("div", "styles-sidebar-toolbar-pane-container"); - this._toolbarPaneElement = toolbarPaneElement; - toolbarPaneContainer.appendChild(toolbarPaneElement); this._sectionsContainer = this.element.createChild("div"); - this._stylesPopoverHelper = new WebInspector.StylesPopoverHelper(); - this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultCSSFormatter()); this.element.classList.add("styles-pane"); @@ -219,7 +203,7 @@ /** * @param {?RegExp} regex */ - _onFilterChanged: function(regex) + onFilterChanged: function(regex) { this._filterRegex = regex; this._updateFilter(); @@ -1219,7 +1203,7 @@ var selectors = this._selectorElement.getElementsByClassName("simple-selector"); var regex = this._parentPane.filterRegex(); for (var i = 0; i < selectors.length; ++i) { - var selectorMatchesFilter = regex && regex.test(selectors[i].textContent); + var selectorMatchesFilter = !!regex && regex.test(selectors[i].textContent); selectors[i].classList.toggle("filter-match", selectorMatchesFilter); } },
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css index 6bf340d..679e521 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
@@ -455,6 +455,7 @@ .styles-sidebar-toolbar-pane-container { position: relative; overflow: hidden; + flex-shrink: 0; } .styles-element-state-pane { @@ -594,8 +595,15 @@ position: relative; } +.styles-sidebar-pane-toolbar-container { + flex-shrink: 0; + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.14); + border-bottom: 1px solid #DDD; +} + .styles-sidebar-pane-toolbar { border-bottom: 1px solid #eee; + flex-shrink: 0; } .styles-sidebar-pane-filter-box {
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index 3e17395..218c2c7 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -121,6 +121,7 @@ Runtime.experiments.register("privateScriptInspection", "Private script inspection"); Runtime.experiments.register("promiseTracker", "Promise inspector"); Runtime.experiments.register("requestBlocking", "Request blocking", true); + Runtime.experiments.register("timelineShowAllEvents", "Show all events on Timeline", true); Runtime.experiments.register("timelineLatencyInfo", "Show input latency events on the Timeline", true); Runtime.experiments.register("securityPanel", "Security panel"); Runtime.experiments.register("showPrimaryLoadWaterfallInNetworkTimeline", "Show primary load waterfall in Network timeline", true);
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Tests.js b/third_party/WebKit/Source/devtools/front_end/main/Tests.js index 739fd19..69c0d8b 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Tests.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Tests.js
@@ -244,7 +244,6 @@ function finishResource(resource, finishTime) { - test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length"); test.assertEquals(25, resource.resourceSize, "Incorrect total data length"); test.releaseControl(); } @@ -267,7 +266,6 @@ function finishResource(resource, finishTime) { - test.assertEquals(219, resource.transferSize, "Incorrect total encoded data length"); test.assertEquals(25, resource.resourceSize, "Incorrect total data length"); test.releaseControl(); } @@ -292,7 +290,8 @@ { if (!resource.responseHeadersText) test.fail("Failure: resource does not have response headers text"); - test.assertEquals(164, resource.responseHeadersText.length, "Incorrect response headers text length"); + var index = resource.responseHeadersText.indexOf("Date:") + test.assertEquals(112, resource.responseHeadersText.substring(index).length, "Incorrect response headers text length"); test.releaseControl(); }
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js index 19c7eb466..651eec4 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
@@ -106,7 +106,7 @@ case "remoteAddress": cell.setTextAndTitle(this._request.remoteAddress()); break; case "cookies": cell.setTextAndTitle(this._arrayLength(this._request.requestCookies)); break; case "setCookies": cell.setTextAndTitle(this._arrayLength(this._request.responseCookies)); break; - case "priority": cell.setTextAndTitle(this._uiLabelForPriority(this._request.initialPriority())); break; + case "priority": cell.setTextAndTitle(WebInspector.uiLabelForPriority(this._request.initialPriority())); break; case "connectionId": cell.setTextAndTitle(this._request.connectionId); break; case "type": this._renderTypeCell(cell); break; case "initiator": this._renderInitiatorCell(cell); break; @@ -550,24 +550,6 @@ } }, - /** - * @param {?NetworkAgent.ResourcePriority} priority - */ - _uiLabelForPriority: function(priority) - { - var labelMap = WebInspector.NetworkDataGridNode._priorityToUILabel; - if (!labelMap) { - WebInspector.NetworkDataGridNode._priorityToUILabel = new Map(); - labelMap = WebInspector.NetworkDataGridNode._priorityToUILabel; - labelMap.set(NetworkAgent.ResourcePriority.VeryLow, WebInspector.UIString("Lowest")); - labelMap.set(NetworkAgent.ResourcePriority.Low, WebInspector.UIString("Low")); - labelMap.set(NetworkAgent.ResourcePriority.Medium, WebInspector.UIString("Medium")); - labelMap.set(NetworkAgent.ResourcePriority.High, WebInspector.UIString("High")); - labelMap.set(NetworkAgent.ResourcePriority.VeryHigh, WebInspector.UIString("Highest")); - } - return priority ? labelMap.get(priority) : WebInspector.UIString("Unknown"); - }, - __proto__: WebInspector.SortableDataGridNode.prototype }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js index bb91c40..34ae65a 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
@@ -1855,7 +1855,7 @@ */ _trimSourceURL: function(text) { - var sourceURLRegex = /\n[\040\t]*\/\*[#@][\040\t]sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/mg; + var sourceURLRegex = /\n[\040\t]*\/\*#[\040\t]sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/mg; return text.replace(sourceURLRegex, ""); },
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js index 55a12edb..d363656c 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/Script.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/Script.js
@@ -62,7 +62,7 @@ SourceMapURLAdded: "SourceMapURLAdded", } -WebInspector.Script.sourceURLRegex = /\n[\040\t]*\/\/[@#]\ssourceURL=\s*(\S*?)\s*$/mg; +WebInspector.Script.sourceURLRegex = /\n[\040\t]*\/\/#\ssourceURL=\s*(\S*?)\s*$/mg; /** * @param {string} source
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js index 02fbd9d..7e0a4a5 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -41,10 +41,11 @@ /** @type {?WebInspector.FlameChart.TimelineData} */ this._timelineData; this._font = "11px " + WebInspector.fontFamily(); - this._filters = [ - WebInspector.TimelineUIUtils.visibleEventsFilter(), - new WebInspector.ExcludeTopLevelFilter() - ]; + this._filters = []; + if (!Runtime.experiments.isEnabled("timelineShowAllEvents")) { + this._filters.push(WebInspector.TimelineUIUtils.visibleEventsFilter()); + this._filters.push(new WebInspector.ExcludeTopLevelFilter()); + } } WebInspector.TimelineFlameChartDataProviderBase.prototype = { @@ -924,6 +925,15 @@ waitingWidth = Math.min(waitingWidth, barWidth - minTransferWidthPx); context.fillStyle = "hsla(0, 0%, 100%, 0.5)"; context.fillRect(barX, barY, waitingWidth, barHeight); + if (typeof request.priority === "string") { + var color = this._colorForPriority(request.priority); + if (color) { + context.fillStyle = "hsl(0, 0%, 100%)"; + context.fillRect(barX, barY, 4, 4); + context.fillStyle = color; + context.fillRect(barX, barY, 3, 3); + } + } return false; }, @@ -952,12 +962,32 @@ var duration = request.endTime - request.startTime; if (request.startTime && isFinite(duration)) value.createChild("span", "timeline-network-info-duration").textContent = Number.millisToString(duration); - value.createChild("span", "timeline-network-info-method").textContent = request.requestMethod; + if (typeof request.priority === "string") { + var div = value.createChild("span", "timeline-network-info-priority"); + div.textContent = WebInspector.uiLabelForPriority(/** @type {!NetworkAgent.ResourcePriority} */ (request.priority)); + div.style.color = this._colorForPriority(request.priority) || "black"; + } value.createChild("span", "timeline-network-info-url").textContent = request.url.trimMiddle(maxURLChars); return [{ title: "", value: value }]; }, /** + * @param {string} priority + * @return {?string} + */ + _colorForPriority: function(priority) + { + switch (/** @type {!NetworkAgent.ResourcePriority} */ (priority)) { + case NetworkAgent.ResourcePriority.VeryLow: return "#080"; + case NetworkAgent.ResourcePriority.Low: return "#6c0"; + case NetworkAgent.ResourcePriority.Medium: return "#fa0"; + case NetworkAgent.ResourcePriority.High: return "#f60"; + case NetworkAgent.ResourcePriority.VeryHigh: return "#f00"; + } + return null; + }, + + /** * @param {!Array.<!WebInspector.TracingModel.Event>} events */ _appendTimelineData: function(events)
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js index 7f127f7..a9d4ddba 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js
@@ -1484,177 +1484,6 @@ /** * @constructor - */ -WebInspector.TimelineModel.ProfileTreeNode = function() -{ - /** @type {number} */ - this.totalTime; - /** @type {number} */ - this.selfTime; - /** @type {string} */ - this.name; - /** @type {string} */ - this.color; - /** @type {string} */ - this.id; - /** @type {!WebInspector.TracingModel.Event} */ - this.event; - /** @type {?Map<string|symbol,!WebInspector.TimelineModel.ProfileTreeNode>} */ - this.children; - /** @type {?WebInspector.TimelineModel.ProfileTreeNode} */ - this.parent; -} - -/** - * @param {!Array<!WebInspector.TracingModel.Event>} events - * @param {number} startTime - * @param {number} endTime - * @param {!Array<!WebInspector.TimelineModel.Filter>} filters - * @param {function(!WebInspector.TracingModel.Event):(string|symbol)=} eventIdCallback - * @return {!WebInspector.TimelineModel.ProfileTreeNode} - */ -WebInspector.TimelineModel.buildTopDownTree = function(events, startTime, endTime, filters, eventIdCallback) -{ - // Temporarily deposit a big enough value that exceeds the max recording time. - var /** @const */ initialTime = 1e7; - var root = new WebInspector.TimelineModel.ProfileTreeNode(); - root.totalTime = initialTime; - root.selfTime = initialTime; - root.name = WebInspector.UIString("Top-Down Chart"); - root.children = /** @type {!Map<string, !WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); - var parent = root; - - /** - * @param {!WebInspector.TracingModel.Event} e - */ - function onStartEvent(e) - { - if (!WebInspector.TimelineModel.isVisible(filters, e)) - return; - var time = e.endTime ? Math.min(endTime, e.endTime) - Math.max(startTime, e.startTime) : 0; - var id = eventIdCallback ? eventIdCallback(e) : Symbol("uniqueEventId"); - if (!parent.children) - parent.children = /** @type {!Map<string,!WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); - var node = parent.children.get(id); - if (node) { - node.selfTime += time; - node.totalTime += time; - } else { - node = new WebInspector.TimelineModel.ProfileTreeNode(); - node.totalTime = time; - node.selfTime = time; - node.parent = parent; - node.id = id; - node.event = e; - parent.children.set(id, node); - } - parent.selfTime -= time; - if (parent.selfTime < 0) { - console.log("Error: Negative self of " + parent.selfTime, e); - parent.selfTime = 0; - } - if (e.endTime) - parent = node; - } - - /** - * @param {!WebInspector.TracingModel.Event} e - */ - function onEndEvent(e) - { - if (!WebInspector.TimelineModel.isVisible(filters, e)) - return; - parent = parent.parent; - } - - var instantEventCallback = eventIdCallback ? undefined : onStartEvent; // Ignore instant events when aggregating. - WebInspector.TimelineModel.forEachEvent(events, onStartEvent, onEndEvent, instantEventCallback, startTime, endTime); - root.totalTime -= root.selfTime; - root.selfTime = 0; - return root; -} - -/** - * @param {!WebInspector.TimelineModel.ProfileTreeNode} topDownTree - * @param {?function(!WebInspector.TimelineModel.ProfileTreeNode):!WebInspector.TimelineModel.ProfileTreeNode=} groupingCallback - * @return {!WebInspector.TimelineModel.ProfileTreeNode} - */ -WebInspector.TimelineModel.buildBottomUpTree = function(topDownTree, groupingCallback) -{ - var buRoot = new WebInspector.TimelineModel.ProfileTreeNode(); - buRoot.selfTime = 0; - buRoot.totalTime = 0; - buRoot.name = WebInspector.UIString("Bottom-Up Chart"); - /** @type {!Map<string, !WebInspector.TimelineModel.ProfileTreeNode>} */ - buRoot.children = new Map(); - var nodesOnStack = /** @type {!Set<string>} */ (new Set()); - if (topDownTree.children) - topDownTree.children.forEach(processNode); - buRoot.totalTime = topDownTree.totalTime; - - /** - * @param {!WebInspector.TimelineModel.ProfileTreeNode} tdNode - */ - function processNode(tdNode) - { - var buParent = groupingCallback && groupingCallback(tdNode) || buRoot; - if (buParent !== buRoot) - buRoot.children.set(buParent.id, buParent); - appendNode(tdNode, buParent); - var hadNode = nodesOnStack.has(tdNode.id); - if (!hadNode) - nodesOnStack.add(tdNode.id); - if (tdNode.children) - tdNode.children.forEach(processNode); - if (!hadNode) - nodesOnStack.delete(tdNode.id); - } - - /** - * @param {!WebInspector.TimelineModel.ProfileTreeNode} tdNode - * @param {!WebInspector.TimelineModel.ProfileTreeNode} buParent - */ - function appendNode(tdNode, buParent) - { - var selfTime = tdNode.selfTime; - var totalTime = tdNode.totalTime; - buParent.selfTime += selfTime; - buParent.totalTime += selfTime; - while (tdNode.parent) { - if (!buParent.children) - buParent.children = /** @type {!Map<string,!WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); - var id = tdNode.id; - var buNode = buParent.children.get(id); - if (!buNode) { - buNode = new WebInspector.TimelineModel.ProfileTreeNode(); - buNode.selfTime = selfTime; - buNode.totalTime = totalTime; - buNode.name = tdNode.name; - buNode.event = tdNode.event; - buNode.id = id; - buParent.children.set(id, buNode); - } else { - buNode.selfTime += selfTime; - if (!nodesOnStack.has(id)) - buNode.totalTime += totalTime; - } - tdNode = tdNode.parent; - buParent = buNode; - } - } - - // Purge zero self time nodes. - var rootChildren = buRoot.children; - for (var item of rootChildren.entries()) { - if (item[1].selfTime === 0) - rootChildren.delete(item[0]); - } - - return buRoot; -} - -/** - * @constructor * @param {!WebInspector.TracingModel.Event} event */ WebInspector.TimelineModel.NetworkRequest = function(event) @@ -1675,6 +1504,8 @@ var eventData = event.args["data"]; if (eventData["mimeType"]) this.mimeType = eventData["mimeType"]; + if ("priority" in eventData) + this.priority = eventData["priority"]; if (event.name === recordType.ResourceFinish) this.endTime = event.startTime; if (!this.responseTime && (event.name === recordType.ResourceReceiveResponse || event.name === recordType.ResourceReceivedData))
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index 82ef278..1c35c2e 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -4,6 +4,29 @@ /** * @constructor + */ +WebInspector.TimelineModel.ProfileTreeNode = function() +{ + /** @type {number} */ + this.totalTime; + /** @type {number} */ + this.selfTime; + /** @type {string} */ + this.name; + /** @type {string} */ + this.color; + /** @type {string} */ + this.id; + /** @type {!WebInspector.TracingModel.Event} */ + this.event; + /** @type {?Map<string|symbol,!WebInspector.TimelineModel.ProfileTreeNode>} */ + this.children; + /** @type {?WebInspector.TimelineModel.ProfileTreeNode} */ + this.parent; +} + +/** + * @constructor * @extends {WebInspector.VBox} * @param {!WebInspector.TimelineModel} model */ @@ -15,10 +38,11 @@ this._model = model; this._linkifier = new WebInspector.Linkifier(); - this._filters = [ - WebInspector.TimelineUIUtils.visibleEventsFilter(), - new WebInspector.ExcludeTopLevelFilter() - ]; + this._filters = []; + if (!Runtime.experiments.isEnabled("timelineShowAllEvents")) { + this._filters.push(WebInspector.TimelineUIUtils.visibleEventsFilter()); + this._filters.push(new WebInspector.ExcludeTopLevelFilter()); + } this._populateToolbar(this.element); @@ -122,6 +146,74 @@ }, /** + * @param {function(!WebInspector.TracingModel.Event):(string|symbol)=} eventIdCallback + * @return {!WebInspector.TimelineModel.ProfileTreeNode} + */ + _buildTopDownTree: function(eventIdCallback) + { + // Temporarily deposit a big enough value that exceeds the max recording time. + var /** @const */ initialTime = 1e7; + var root = new WebInspector.TimelineModel.ProfileTreeNode(); + root.totalTime = initialTime; + root.selfTime = initialTime; + root.name = WebInspector.UIString("Top-Down Chart"); + root.children = /** @type {!Map<string, !WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); + var parent = root; + + /** + * @this {WebInspector.TimelineTreeView} + * @param {!WebInspector.TracingModel.Event} e + */ + function onStartEvent(e) + { + if (!WebInspector.TimelineModel.isVisible(this._filters, e)) + return; + var time = e.endTime ? Math.min(this._endTime, e.endTime) - Math.max(this._startTime, e.startTime) : 0; + var id = eventIdCallback ? eventIdCallback(e) : Symbol("uniqueEventId"); + if (!parent.children) + parent.children = /** @type {!Map<string,!WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); + var node = parent.children.get(id); + if (node) { + node.selfTime += time; + node.totalTime += time; + } else { + node = new WebInspector.TimelineModel.ProfileTreeNode(); + node.totalTime = time; + node.selfTime = time; + node.parent = parent; + node.id = id; + node.event = e; + parent.children.set(id, node); + } + parent.selfTime -= time; + if (parent.selfTime < 0) { + console.log("Error: Negative self of " + parent.selfTime, e); + parent.selfTime = 0; + } + if (e.endTime) + parent = node; + } + + /** + * @this {WebInspector.TimelineTreeView} + * @param {!WebInspector.TracingModel.Event} e + */ + function onEndEvent(e) + { + if (!WebInspector.TimelineModel.isVisible(this._filters, e)) + return; + parent = parent.parent; + } + + var instantEventCallback = eventIdCallback ? undefined : onStartEvent.bind(this); // Ignore instant events when aggregating. + var events = this._model.mainThreadEvents(); + WebInspector.TimelineModel.forEachEvent(events, onStartEvent.bind(this), onEndEvent.bind(this), instantEventCallback, this._startTime, this._endTime); + root.totalTime -= root.selfTime; + root.selfTime = 0; + return root; + }, + + /** * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>} columns */ _populateColumns: function(columns) @@ -629,7 +721,7 @@ */ _buildTree: function() { - var topDown = WebInspector.TimelineModel.buildTopDownTree(this._model.mainThreadEvents(), this._startTime, this._endTime, this._filters, WebInspector.AggregatedTimelineTreeView.eventId); + var topDown = this._buildTopDownTree(WebInspector.AggregatedTimelineTreeView.eventId); return this._performTopDownTreeGrouping(topDown); }, @@ -675,20 +767,90 @@ */ _buildTree: function() { - var topDown = WebInspector.TimelineModel.buildTopDownTree(this._model.mainThreadEvents(), this._startTime, this._endTime, this._filters, WebInspector.AggregatedTimelineTreeView.eventId); - return this._buildBottomUpTree(topDown); + var topDown = this._buildTopDownTree(WebInspector.AggregatedTimelineTreeView.eventId); + this._groupNodes = new Map(); + var nodeToGroupId = this._nodeToGroupIdFunction(); + var nodeToGroupNode = nodeToGroupId ? this._nodeToGroupNode.bind(this, nodeToGroupId) : null; + return this._buildBottomUpTree(topDown, nodeToGroupNode); }, /** * @param {!WebInspector.TimelineModel.ProfileTreeNode} topDownTree + * @param {?function(!WebInspector.TimelineModel.ProfileTreeNode):!WebInspector.TimelineModel.ProfileTreeNode=} groupingCallback * @return {!WebInspector.TimelineModel.ProfileTreeNode} */ - _buildBottomUpTree: function(topDownTree) + _buildBottomUpTree: function(topDownTree, groupingCallback) { - this._groupNodes = new Map(); - var nodeToGroupId = this._nodeToGroupIdFunction(); - var nodeToGroupNode = nodeToGroupId ? this._nodeToGroupNode.bind(this, nodeToGroupId) : null; - return WebInspector.TimelineModel.buildBottomUpTree(topDownTree, nodeToGroupNode); + var buRoot = new WebInspector.TimelineModel.ProfileTreeNode(); + buRoot.selfTime = 0; + buRoot.totalTime = 0; + buRoot.name = WebInspector.UIString("Bottom-Up Chart"); + /** @type {!Map<string, !WebInspector.TimelineModel.ProfileTreeNode>} */ + buRoot.children = new Map(); + var nodesOnStack = /** @type {!Set<string>} */ (new Set()); + if (topDownTree.children) + topDownTree.children.forEach(processNode); + buRoot.totalTime = topDownTree.totalTime; + + /** + * @param {!WebInspector.TimelineModel.ProfileTreeNode} tdNode + */ + function processNode(tdNode) + { + var buParent = groupingCallback && groupingCallback(tdNode) || buRoot; + if (buParent !== buRoot) + buRoot.children.set(buParent.id, buParent); + appendNode(tdNode, buParent); + var hadNode = nodesOnStack.has(tdNode.id); + if (!hadNode) + nodesOnStack.add(tdNode.id); + if (tdNode.children) + tdNode.children.forEach(processNode); + if (!hadNode) + nodesOnStack.delete(tdNode.id); + } + + /** + * @param {!WebInspector.TimelineModel.ProfileTreeNode} tdNode + * @param {!WebInspector.TimelineModel.ProfileTreeNode} buParent + */ + function appendNode(tdNode, buParent) + { + var selfTime = tdNode.selfTime; + var totalTime = tdNode.totalTime; + buParent.selfTime += selfTime; + buParent.totalTime += selfTime; + while (tdNode.parent) { + if (!buParent.children) + buParent.children = /** @type {!Map<string,!WebInspector.TimelineModel.ProfileTreeNode>} */ (new Map()); + var id = tdNode.id; + var buNode = buParent.children.get(id); + if (!buNode) { + buNode = new WebInspector.TimelineModel.ProfileTreeNode(); + buNode.selfTime = selfTime; + buNode.totalTime = totalTime; + buNode.name = tdNode.name; + buNode.event = tdNode.event; + buNode.id = id; + buParent.children.set(id, buNode); + } else { + buNode.selfTime += selfTime; + if (!nodesOnStack.has(id)) + buNode.totalTime += totalTime; + } + tdNode = tdNode.parent; + buParent = buNode; + } + } + + // Purge zero self time nodes. + var rootChildren = buRoot.children; + for (var item of rootChildren.entries()) { + if (item[1].selfTime === 0) + rootChildren.delete(item[0]); + } + + return buRoot; }, __proto__: WebInspector.AggregatedTimelineTreeView.prototype @@ -728,7 +890,7 @@ */ _buildTree: function() { - this._currentTree = WebInspector.TimelineModel.buildTopDownTree(this._model.mainThreadEvents(), this._startTime, this._endTime, this._filters); + this._currentTree = this._buildTopDownTree(); return this._currentTree; },
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js index c8ec245..bb190fd 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -179,7 +179,7 @@ var result = eventStyles[event.name]; if (!result) { - result = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Unknown: %s", event.name), WebInspector.TimelineUIUtils.categories()["other"], true); + result = new WebInspector.TimelineRecordStyle(event.name, WebInspector.TimelineUIUtils.categories()["other"], true); eventStyles[event.name] = result; } return result; @@ -648,6 +648,10 @@ contentHelper.appendTextRow(WebInspector.UIString("Status Code"), eventData["statusCode"]); if (eventData["mimeType"]) contentHelper.appendTextRow(WebInspector.UIString("MIME Type"), eventData["mimeType"]); + if ("priority" in eventData) { + var priority = WebInspector.uiLabelForPriority(eventData["priority"]); + contentHelper.appendTextRow(WebInspector.UIString("Priority"), priority); + } if (eventData["encodedDataLength"]) contentHelper.appendTextRow(WebInspector.UIString("Encoded Data Length"), WebInspector.UIString("%d Bytes", eventData["encodedDataLength"])); break; @@ -864,6 +868,10 @@ items.push({ title: WebInspector.UIString("Duration"), value: Number.millisToString(duration, true) }); if (request.requestMethod) items.push({ title: WebInspector.UIString("Request Method"), value: request.requestMethod }); + if (typeof request.priority === "string") { + var priority = WebInspector.uiLabelForPriority(/** @type {!NetworkAgent.ResourcePriority} */ (request.priority)); + items.push({ title: WebInspector.UIString("Priority"), value: priority }); + } if (request.mimeType) items.push({ title: WebInspector.UIString("Mime Type"), value: request.mimeType }); return items;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js index 66026220..2d84d8cd 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1736,5 +1736,25 @@ } } +/** + * @param {?NetworkAgent.ResourcePriority} priority + * @return {string} + */ +WebInspector.uiLabelForPriority = function(priority) +{ + var labelMap = WebInspector.uiLabelForPriority._priorityToUILabel; + if (!labelMap) { + labelMap = new Map([ + [NetworkAgent.ResourcePriority.VeryLow, WebInspector.UIString("Lowest")], + [NetworkAgent.ResourcePriority.Low, WebInspector.UIString("Low")], + [NetworkAgent.ResourcePriority.Medium, WebInspector.UIString("Medium")], + [NetworkAgent.ResourcePriority.High, WebInspector.UIString("High")], + [NetworkAgent.ResourcePriority.VeryHigh, WebInspector.UIString("Highest")] + ]); + WebInspector.uiLabelForPriority._priorityToUILabel = labelMap; + } + return labelMap.get(priority) || WebInspector.UIString("Unknown"); +} + /** @type {!WebInspector.ThemeSupport} */ WebInspector.themeSupport;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css b/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css index e54ca61..e417ff2 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css
@@ -86,9 +86,5 @@ } .flame-chart-entry-info table tr td span.timeline-network-info-duration { - color: darkgreen; -} - -.flame-chart-entry-info table tr td span.timeline-network-info-method { color: darkblue; }
diff --git a/third_party/WebKit/Source/modules/InitModules.cpp b/third_party/WebKit/Source/modules/InitModules.cpp index ac4736b2..e209ffd2 100644 --- a/third_party/WebKit/Source/modules/InitModules.cpp +++ b/third_party/WebKit/Source/modules/InitModules.cpp
@@ -15,7 +15,6 @@ #include "modules/IndexedDBNames.h" #include "modules/accessibility/AXObjectCacheImpl.h" #include "modules/canvas2d/CanvasRenderingContext2D.h" -#include "modules/compositorworker/CompositorWorkerManager.h" #include "modules/filesystem/DraggedIsolatedFileSystemImpl.h" #include "modules/webdatabase/DatabaseManager.h" #include "modules/webgl/WebGL2RenderingContext.h" @@ -43,9 +42,6 @@ CoreInitializer::init(); - if (RuntimeEnabledFeatures::compositorWorkerEnabled()) - CompositorWorkerManager::initialize(); - // Canvas context types must be registered with the HTMLCanvasElement. HTMLCanvasElement::registerRenderingContextFactory(adoptPtr(new CanvasRenderingContext2D::Factory())); HTMLCanvasElement::registerRenderingContextFactory(adoptPtr(new WebGLRenderingContext::Factory())); @@ -56,8 +52,6 @@ void ModulesInitializer::terminateThreads() { - if (RuntimeEnabledFeatures::compositorWorkerEnabled()) - CompositorWorkerManager::shutdown(); DatabaseManager::terminateDatabaseThread(); }
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.h index 49f8768..9a8f05a 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.h +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.h
@@ -6,6 +6,7 @@ #define CompositorWorker_h #include "core/workers/InProcessWorkerBase.h" +#include "modules/ModulesExport.h" #include "wtf/PassRefPtr.h" #include "wtf/text/AtomicString.h" @@ -15,7 +16,7 @@ class ExecutionContext; class WorkerGlobalScopeProxy; -class CompositorWorker final : public InProcessWorkerBase { +class MODULES_EXPORT CompositorWorker final : public InProcessWorkerBase { DEFINE_WRAPPERTYPEINFO(); public: static CompositorWorker* create(ExecutionContext*, const String& url, ExceptionState&);
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.cpp deleted file mode 100644 index d450d294..0000000 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.cpp +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "config.h" -#include "modules/compositorworker/CompositorWorkerManager.h" - -#include "bindings/core/v8/V8Binding.h" -#include "bindings/core/v8/V8GCController.h" -#include "bindings/core/v8/V8Initializer.h" -#include "bindings/core/v8/V8PerIsolateData.h" -#include "platform/ThreadSafeFunctional.h" -#include "platform/WebThreadSupportingGC.h" -#include "wtf/MainThread.h" -#include "wtf/ThreadingPrimitives.h" - -namespace blink { - -namespace { - -static CompositorWorkerManager* s_instance = nullptr; - -Mutex& singletonMutex() -{ - AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); - return mutex; -} - -void destroyThread(WebThread* thread) -{ - delete thread; -} - -} // namespace - -void CompositorWorkerManager::initialize() -{ - MutexLocker lock(singletonMutex()); - ASSERT(!s_instance); - s_instance = new CompositorWorkerManager(); -} - -void CompositorWorkerManager::shutdown() -{ - MutexLocker lock(singletonMutex()); - ASSERT(s_instance); - delete s_instance; - s_instance = nullptr; -} - -CompositorWorkerManager* CompositorWorkerManager::instance() -{ - MutexLocker lock(singletonMutex()); - ASSERT(s_instance); - return s_instance; -} - -CompositorWorkerManager::CompositorWorkerManager() -{ -} - -CompositorWorkerManager::~CompositorWorkerManager() -{ -} - -WebThreadSupportingGC& CompositorWorkerManager::compositorWorkerThread() -{ - MutexLocker lock(m_mutex); - if (!m_thread) { - ASSERT(isMainThread()); - ASSERT(!m_workerCount); - // TODO(sadrul): Instead of creating a new thread, retrieve the thread from - // Platform using a more specialized function - // (e.g. Platform::compositorWorkerThread()). - m_platformThread = adoptPtr(Platform::current()->createThread("CompositorWorker Thread")); - m_thread = WebThreadSupportingGC::createForThread(m_platformThread.get()); - } - return *m_thread.get(); -} - -void CompositorWorkerManager::initializeBackingThread() -{ - ASSERT(m_thread->isCurrentThread()); - MutexLocker lock(m_mutex); - ++m_workerCount; - if (m_workerCount > 1) - return; - - m_thread->initialize(); - - // Initialize the isolate at the same time. - ASSERT(!m_isolate); - m_isolate = V8PerIsolateData::initialize(); - V8Initializer::initializeWorker(m_isolate); - - OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(m_isolate)); - ThreadState::current()->addInterruptor(interruptor.release()); - ThreadState::current()->registerTraceDOMWrappers(m_isolate, V8GCController::traceDOMWrappers); -} - -void CompositorWorkerManager::shutdownBackingThread() -{ - MutexLocker lock(m_mutex); - ASSERT(m_thread->isCurrentThread()); - ASSERT(m_workerCount > 0); - --m_workerCount; - if (m_workerCount == 0) { - m_thread->shutdown(); - m_thread = nullptr; - Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(destroyThread, AllowCrossThreadAccess(m_platformThread.leakPtr()))); - } -} - -v8::Isolate* CompositorWorkerManager::initializeIsolate() -{ - MutexLocker lock(m_mutex); - ASSERT(m_thread->isCurrentThread()); - ASSERT(m_isolate); - // It is safe to use the existing isolate even if TerminateExecution() has been - // called on it, without calling CancelTerminateExecution(). - return m_isolate; -} - -void CompositorWorkerManager::willDestroyIsolate() -{ - MutexLocker lock(m_mutex); - ASSERT(m_thread->isCurrentThread()); - if (m_workerCount == 1) - V8PerIsolateData::willBeDestroyed(m_isolate); -} - -void CompositorWorkerManager::destroyIsolate() -{ - MutexLocker lock(m_mutex); - if (!m_thread) { - ASSERT(m_workerCount == 0); - V8PerIsolateData::destroy(m_isolate); - m_isolate = nullptr; - } -} - -void CompositorWorkerManager::terminateV8Execution() -{ - MutexLocker lock(m_mutex); - ASSERT(isMainThread()); - if (m_workerCount > 1) - return; - - v8::V8::TerminateExecution(m_isolate); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.h deleted file mode 100644 index 1a70e99..0000000 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManager.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CompositorWorkerManager_h -#define CompositorWorkerManager_h - -#include "modules/ModulesExport.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/ThreadingPrimitives.h" -#include <v8.h> - -namespace blink { - -class V8IsolateInterruptor; -class WebThread; -class WebThreadSupportingGC; - -class MODULES_EXPORT CompositorWorkerManager final { - USING_FAST_MALLOC(CompositorWorkerManager); -public: - static void initialize(); - static void shutdown(); - - static CompositorWorkerManager* instance(); - - // Returns the thread used for compositor workers. This creates a new thread if a - // thread doesn't already exist. - WebThreadSupportingGC& compositorWorkerThread(); - - // Attempts to initialize/shutdown a thread if necessary. Does nothing if the thread - // is already initialized, or if the thread has more than one active workers at the - // time of shutdown. - void initializeBackingThread(); - void shutdownBackingThread(); - - v8::Isolate* initializeIsolate(); - void willDestroyIsolate(); - void destroyIsolate(); - void terminateV8Execution(); - -private: - friend class CompositorWorkerManagerTest; - - CompositorWorkerManager(); - ~CompositorWorkerManager(); - - Mutex m_mutex; - OwnPtr<WebThreadSupportingGC> m_thread; - OwnPtr<WebThread> m_platformThread; - int m_workerCount = 0; - v8::Isolate* m_isolate = nullptr; -}; - -} // namespace blink - -#endif // CompositorWorkerManager_h
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp index fa42002..9bdd80eb 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
@@ -5,17 +5,142 @@ #include "config.h" #include "modules/compositorworker/CompositorWorkerThread.h" +#include "bindings/core/v8/V8GCController.h" #include "bindings/core/v8/V8Initializer.h" #include "core/workers/WorkerObjectProxy.h" #include "core/workers/WorkerThreadStartupData.h" #include "modules/compositorworker/CompositorWorkerGlobalScope.h" -#include "modules/compositorworker/CompositorWorkerManager.h" +#include "platform/ThreadSafeFunctional.h" +#include "platform/TraceEvent.h" #include "public/platform/Platform.h" namespace blink { +namespace { + +void destroyThread(WebThreadSupportingGC* thread) +{ + ASSERT(isMainThread()); + // The destructor for |thread| will block until all tasks have completed. + // This guarantees that shutdown will finish before the thread is destroyed. + delete thread; +} + +class CompositorWorkerSharedState { +public: + static CompositorWorkerSharedState& instance() + { + AtomicallyInitializedStaticReference(CompositorWorkerSharedState, compositorWorkerSharedState, (new CompositorWorkerSharedState())); + return compositorWorkerSharedState; + } + + WebThreadSupportingGC* compositorWorkerThread() + { + MutexLocker lock(m_mutex); + if (!m_thread && isMainThread()) { + ASSERT(!m_workerCount); + WebThread* platformThread = Platform::current()->compositorThread(); + m_thread = WebThreadSupportingGC::createForThread(platformThread); + } + return m_thread.get(); + } + + void initializeBackingThread() + { + MutexLocker lock(m_mutex); + ASSERT(m_thread->isCurrentThread()); + ++m_workerCount; + if (m_workerCount > 1) + return; + + m_thread->initialize(); + + // Initialize the isolate at the same time. + ASSERT(!m_isolate); + m_isolate = V8PerIsolateData::initialize(); + V8Initializer::initializeWorker(m_isolate); + + OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(m_isolate)); + ThreadState::current()->addInterruptor(interruptor.release()); + ThreadState::current()->registerTraceDOMWrappers(m_isolate, V8GCController::traceDOMWrappers); + } + + void shutdownBackingThread() + { + MutexLocker lock(m_mutex); + ASSERT(m_thread->isCurrentThread()); + ASSERT(m_workerCount > 0); + --m_workerCount; + if (m_workerCount == 0) { + m_thread->shutdown(); + Platform::current()->mainThread()->taskRunner()->postTask( + BLINK_FROM_HERE, threadSafeBind(destroyThread, AllowCrossThreadAccess(m_thread.leakPtr()))); + } + } + + v8::Isolate* initializeIsolate() + { + MutexLocker lock(m_mutex); + ASSERT(m_thread->isCurrentThread()); + ASSERT(m_isolate); + // It is safe to use the existing isolate even if TerminateExecution() has been + // called on it, without calling CancelTerminateExecution(). + return m_isolate; + } + + void willDestroyIsolate() + { + MutexLocker lock(m_mutex); + ASSERT(m_thread->isCurrentThread()); + if (m_workerCount == 1) + V8PerIsolateData::willBeDestroyed(m_isolate); + } + + void destroyIsolate() + { + MutexLocker lock(m_mutex); + if (!m_thread) { + ASSERT(m_workerCount == 0); + V8PerIsolateData::destroy(m_isolate); + m_isolate = nullptr; + } + } + + void terminateV8Execution() + { + MutexLocker lock(m_mutex); + ASSERT(isMainThread()); + if (m_workerCount > 1) + return; + + v8::V8::TerminateExecution(m_isolate); + } + + bool hasThreadForTest() + { + return m_thread; + } + + bool hasIsolateForTest() + { + return m_isolate; + } + +private: + CompositorWorkerSharedState() {} + ~CompositorWorkerSharedState() {} + + Mutex m_mutex; + OwnPtr<WebThreadSupportingGC> m_thread; + int m_workerCount = 0; + v8::Isolate* m_isolate = nullptr; +}; + +} // namespace + PassRefPtr<CompositorWorkerThread> CompositorWorkerThread::create(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, double timeOrigin) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::create"); ASSERT(isMainThread()); return adoptRef(new CompositorWorkerThread(workerLoaderProxy, workerObjectProxy, timeOrigin)); } @@ -31,44 +156,65 @@ { } +WebThreadSupportingGC* CompositorWorkerThread::sharedBackingThread() +{ + return CompositorWorkerSharedState::instance().compositorWorkerThread(); +} + PassRefPtrWillBeRawPtr<WorkerGlobalScope> CompositorWorkerThread::createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData> startupData) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::createWorkerGlobalScope"); return CompositorWorkerGlobalScope::create(this, startupData, m_timeOrigin); } WebThreadSupportingGC& CompositorWorkerThread::backingThread() { - return CompositorWorkerManager::instance()->compositorWorkerThread(); + return *CompositorWorkerSharedState::instance().compositorWorkerThread(); } void CompositorWorkerThread::initializeBackingThread() { - CompositorWorkerManager::instance()->initializeBackingThread(); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::initializeBackingThread"); + CompositorWorkerSharedState::instance().initializeBackingThread(); } void CompositorWorkerThread::shutdownBackingThread() { - CompositorWorkerManager::instance()->shutdownBackingThread(); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::shutdownBackingThread"); + CompositorWorkerSharedState::instance().shutdownBackingThread(); } v8::Isolate* CompositorWorkerThread::initializeIsolate() { - return CompositorWorkerManager::instance()->initializeIsolate(); + return CompositorWorkerSharedState::instance().initializeIsolate(); } void CompositorWorkerThread::willDestroyIsolate() { - CompositorWorkerManager::instance()->willDestroyIsolate(); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::willDestroyIsolate"); + CompositorWorkerSharedState::instance().willDestroyIsolate(); } void CompositorWorkerThread::destroyIsolate() { - CompositorWorkerManager::instance()->destroyIsolate(); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::destroyIsolate"); + CompositorWorkerSharedState::instance().destroyIsolate(); } void CompositorWorkerThread::terminateV8Execution() { - CompositorWorkerManager::instance()->terminateV8Execution(); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::terminateV8Execution"); + CompositorWorkerSharedState::instance().terminateV8Execution(); +} + +bool CompositorWorkerThread::hasThreadForTest() +{ + return CompositorWorkerSharedState::instance().hasThreadForTest(); +} + +bool CompositorWorkerThread::hasIsolateForTest() +{ + return CompositorWorkerSharedState::instance().hasIsolateForTest(); } } // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h index fe0ffe83..de0b407 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
@@ -20,6 +20,12 @@ WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; } + // Returns the shared backing thread for all CompositorWorkers. + static WebThreadSupportingGC* sharedBackingThread(); + + static bool hasThreadForTest(); + static bool hasIsolateForTest(); + protected: CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy>, WorkerObjectProxy&, double timeOrigin);
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManagerTest.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp similarity index 81% rename from third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManagerTest.cpp rename to third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp index a0655a79..a45c182 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerManagerTest.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
@@ -3,7 +3,7 @@ // found in the LICENSE file. #include "config.h" -#include "modules/compositorworker/CompositorWorkerManager.h" +#include "modules/compositorworker/CompositorWorkerThread.h" #include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/V8GCController.h" @@ -12,10 +12,10 @@ #include "core/workers/WorkerLoaderProxy.h" #include "core/workers/WorkerObjectProxy.h" #include "core/workers/WorkerThreadStartupData.h" -#include "modules/compositorworker/CompositorWorkerThread.h" #include "platform/NotImplemented.h" #include "platform/ThreadSafeFunctional.h" #include "platform/heap/Handle.h" +#include "platform/testing/TestingPlatformSupport.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebWaitableEvent.h" @@ -32,7 +32,7 @@ { } - ~TestCompositorWorkerThread() override { } + ~TestCompositorWorkerThread() override {} void setCallbackAfterV8Termination(PassOwnPtr<Function<void()>> callback) { @@ -51,9 +51,11 @@ if (m_v8TerminationCallback) (*m_v8TerminationCallback)(); } + void willDestroyIsolate() override { - V8GCController::collectAllGarbageForTesting(v8::Isolate::GetCurrent()); + v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection); + Heap::collectAllGarbage(); CompositorWorkerThread::willDestroyIsolate(); } @@ -70,16 +72,16 @@ } // (Empty) WorkerReportingProxy implementation: - virtual void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, int exceptionId) { } - void reportConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>) override { } - void postMessageToPageInspector(const String&) override { } - void postWorkerConsoleAgentEnabled() override { } + virtual void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, int exceptionId) {} + void reportConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>) override {} + void postMessageToPageInspector(const String&) override {} + void postWorkerConsoleAgentEnabled() override {} - void didEvaluateWorkerScript(bool success) override { } - void workerGlobalScopeStarted(WorkerGlobalScope*) override { } - void workerGlobalScopeClosed() override { } - void workerThreadTerminated() override { } - void willDestroyWorkerGlobalScope() override { } + void didEvaluateWorkerScript(bool success) override {} + void workerGlobalScopeStarted(WorkerGlobalScope*) override {} + void workerGlobalScopeClosed() override {} + void workerThreadTerminated() override {} + void willDestroyWorkerGlobalScope() override {} ExecutionContext* executionContext() override { return m_executionContext.get(); } @@ -93,9 +95,32 @@ RefPtrWillBePersistent<ExecutionContext> m_executionContext; }; +class CompositorWorkerTestPlatform : public TestingPlatformSupport { +public: + CompositorWorkerTestPlatform() + : m_thread(adoptPtr(m_oldPlatform->createThread("Compositor"))) + { + } + + WebThread* compositorThread() const override + { + return m_thread.get(); + } + + WebWaitableEvent* createWaitableEvent( + WebWaitableEvent::ResetPolicy policy, + WebWaitableEvent::InitialState state) override + { + return m_oldPlatform->createWaitableEvent(policy, state); + } + +private: + OwnPtr<WebThread> m_thread; +}; + } // namespace -class CompositorWorkerManagerTest : public ::testing::Test { +class CompositorWorkerThreadTest : public ::testing::Test { public: void SetUp() override { @@ -106,8 +131,8 @@ void TearDown() override { - ASSERT(!managerHasThread()); - ASSERT(!managerHasIsolate()); + ASSERT(!hasThread()); + ASSERT(!hasIsolate()); m_page.clear(); } @@ -137,7 +162,7 @@ void checkWorkerCanExecuteScript(WorkerThread* worker) { OwnPtr<WebWaitableEvent> waitEvent = adoptPtr(Platform::current()->createWaitableEvent()); - worker->backingThread().platformThread().taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CompositorWorkerManagerTest::executeScriptInWorker, AllowCrossThreadAccess(this), + worker->backingThread().platformThread().taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CompositorWorkerThreadTest::executeScriptInWorker, AllowCrossThreadAccess(this), AllowCrossThreadAccess(worker), AllowCrossThreadAccess(waitEvent.get()))); waitEvent->wait(); } @@ -148,14 +173,14 @@ waitEvent->wait(); } - bool managerHasThread() const + bool hasThread() const { - return CompositorWorkerManager::instance()->m_thread; + return CompositorWorkerThread::hasThreadForTest(); } - bool managerHasIsolate() const + bool hasIsolate() const { - return CompositorWorkerManager::instance()->m_isolate; + return CompositorWorkerThread::hasIsolateForTest(); } private: @@ -170,9 +195,10 @@ OwnPtr<DummyPageHolder> m_page; RefPtr<SecurityOrigin> m_securityOrigin; OwnPtr<WorkerObjectProxy> m_objectProxy; + CompositorWorkerTestPlatform m_testPlatform; }; -TEST_F(CompositorWorkerManagerTest, Basic) +TEST_F(CompositorWorkerThreadTest, Basic) { OwnPtr<WebWaitableEvent> creationEvent = adoptPtr(Platform::current()->createWaitableEvent()); RefPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get()); @@ -182,12 +208,12 @@ } // Tests that the same WebThread is used for new workers if the WebThread is still alive. -TEST_F(CompositorWorkerManagerTest, CreateSecondAndTerminateFirst) +TEST_F(CompositorWorkerThreadTest, CreateSecondAndTerminateFirst) { // Create the first worker and wait until it is initialized. OwnPtr<WebWaitableEvent> firstCreationEvent = adoptPtr(Platform::current()->createWaitableEvent()); RefPtr<CompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get()); - WebThreadSupportingGC* firstThread = &CompositorWorkerManager::instance()->compositorWorkerThread(); + WebThreadSupportingGC* firstThread = CompositorWorkerThread::sharedBackingThread(); ASSERT(firstThread); waitForWaitableEventAfterIteratingCurrentLoop(firstCreationEvent.get()); v8::Isolate* firstIsolate = firstWorker->isolate(); @@ -200,7 +226,7 @@ // Wait until the second worker is initialized. Verify that the second worker is using the same // thread and Isolate as the first worker. - WebThreadSupportingGC* secondThread = &CompositorWorkerManager::instance()->compositorWorkerThread(); + WebThreadSupportingGC* secondThread = CompositorWorkerThread::sharedBackingThread(); ASSERT(secondThread); waitForWaitableEventAfterIteratingCurrentLoop(secondCreationEvent.get()); EXPECT_EQ(firstThread, secondThread); @@ -222,12 +248,12 @@ } // Tests that a new WebThread is created if all existing workers are terminated before a new worker is created. -TEST_F(CompositorWorkerManagerTest, TerminateFirstAndCreateSecond) +TEST_F(CompositorWorkerThreadTest, TerminateFirstAndCreateSecond) { // Create the first worker, wait until it is initialized, and terminate it. OwnPtr<WebWaitableEvent> creationEvent = adoptPtr(Platform::current()->createWaitableEvent()); RefPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get()); - WebThreadSupportingGC* firstThread = &CompositorWorkerManager::instance()->compositorWorkerThread(); + WebThreadSupportingGC* firstThread = CompositorWorkerThread::sharedBackingThread(); waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get()); ASSERT(compositorWorker->isolate()); compositorWorker->terminateAndWait(); @@ -236,7 +262,7 @@ // thread will have been destroyed after destroying the first worker. creationEvent = adoptPtr(Platform::current()->createWaitableEvent()); compositorWorker = createCompositorWorker(creationEvent.get()); - WebThreadSupportingGC* secondThread = &CompositorWorkerManager::instance()->compositorWorkerThread(); + WebThreadSupportingGC* secondThread = CompositorWorkerThread::sharedBackingThread(); EXPECT_NE(firstThread, secondThread); waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get()); @@ -250,7 +276,7 @@ } // Tests that v8::Isolate and WebThread are correctly set-up if a worker is created while another is terminating. -TEST_F(CompositorWorkerManagerTest, CreatingSecondDuringTerminationOfFirst) +TEST_F(CompositorWorkerThreadTest, CreatingSecondDuringTerminationOfFirst) { OwnPtr<WebWaitableEvent> firstCreationEvent = adoptPtr(Platform::current()->createWaitableEvent()); RefPtr<TestCompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get()); @@ -262,7 +288,7 @@ // the first worker terminates its isolate. OwnPtr<WebWaitableEvent> secondCreationEvent = adoptPtr(Platform::current()->createWaitableEvent()); RefPtr<CompositorWorkerThread> secondWorker; - firstWorker->setCallbackAfterV8Termination(bind(&CompositorWorkerManagerTest::createWorkerAdapter, this, &secondWorker, secondCreationEvent.get())); + firstWorker->setCallbackAfterV8Termination(bind(&CompositorWorkerThreadTest::createWorkerAdapter, this, &secondWorker, secondCreationEvent.get())); firstWorker->terminateAndWait(); ASSERT(secondWorker);
diff --git a/third_party/WebKit/Source/modules/fetch/Response.cpp b/third_party/WebKit/Source/modules/fetch/Response.cpp index 7ca6de4..ac92166 100644 --- a/third_party/WebKit/Source/modules/fetch/Response.cpp +++ b/third_party/WebKit/Source/modules/fetch/Response.cpp
@@ -13,6 +13,7 @@ #include "core/html/FormData.h" #include "modules/fetch/BodyStreamBuffer.h" #include "modules/fetch/FetchBlobDataConsumerHandle.h" +#include "modules/fetch/FetchFormDataConsumerHandle.h" #include "modules/fetch/ResponseInit.h" #include "platform/network/EncodedFormData.h" #include "platform/network/HTTPHeaderMap.h" @@ -96,90 +97,53 @@ Response* Response::create(ExecutionContext* context, ExceptionState& exceptionState) { - return create(context, nullptr, ResponseInit(), exceptionState); + return create(context, nullptr, String(), ResponseInit(), exceptionState); } -Response* Response::create(ExecutionContext* context, const BodyInit& body, const Dictionary& responseInit, ExceptionState& exceptionState) +Response* Response::create(ExecutionContext* context, const BodyInit& body, const Dictionary& init, ExceptionState& exceptionState) { ASSERT(!body.isNull()); - if (body.isBlob()) - return create(context, body.getAsBlob(), ResponseInit(responseInit, exceptionState), exceptionState); - if (body.isUSVString()) { - OwnPtr<BlobData> blobData = BlobData::create(); - blobData->appendText(body.getAsUSVString(), false); - // "Set |Content-Type| to `text/plain;charset=UTF-8`." - blobData->setContentType("text/plain;charset=UTF-8"); - const long long length = blobData->length(); - Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); - return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState); + OwnPtr<FetchDataConsumerHandle> bodyHandle; + String contentType; + if (body.isBlob()) { + bodyHandle = FetchBlobDataConsumerHandle::create(context, body.getAsBlob()->blobDataHandle()); + contentType = body.getAsBlob()->type(); + } else if (body.isUSVString()) { + bodyHandle = FetchFormDataConsumerHandle::create(body.getAsUSVString()); + contentType = "text/plain;charset=UTF-8"; + } else if (body.isArrayBuffer()) { + bodyHandle = FetchFormDataConsumerHandle::create(body.getAsArrayBuffer()); + } else if (body.isArrayBufferView()) { + bodyHandle = FetchFormDataConsumerHandle::create(body.getAsArrayBufferView()); + } else if (body.isFormData()) { + RefPtr<EncodedFormData> formData = body.getAsFormData()->encodeMultiPartFormData(); + // Here we handle formData->boundary() as a C-style string. See + // FormDataEncoder::generateUniqueBoundaryString. + contentType = AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + formData->boundary().data(); + bodyHandle = FetchFormDataConsumerHandle::create(context, formData.release()); + } else { + ASSERT_NOT_REACHED(); + return nullptr; } - if (body.isArrayBuffer()) { - RefPtr<DOMArrayBuffer> arrayBuffer = body.getAsArrayBuffer(); - OwnPtr<BlobData> blobData = BlobData::create(); - blobData->appendBytes(arrayBuffer->data(), arrayBuffer->byteLength()); - const long long length = blobData->length(); - Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); - return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState); - } - if (body.isArrayBufferView()) { - RefPtr<DOMArrayBufferView> arrayBufferView = body.getAsArrayBufferView(); - OwnPtr<BlobData> blobData = BlobData::create(); - blobData->appendBytes(arrayBufferView->baseAddress(), arrayBufferView->byteLength()); - const long long length = blobData->length(); - Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); - return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState); - } - if (body.isFormData()) { - FormData* domFormData = body.getAsFormData(); - OwnPtr<BlobData> blobData = BlobData::create(); - // FIXME: the same code exist in RequestInit::RequestInit(). - RefPtr<EncodedFormData> httpBody = domFormData->encodeMultiPartFormData(); - for (size_t i = 0; i < httpBody->elements().size(); ++i) { - const FormDataElement& element = httpBody->elements()[i]; - switch (element.m_type) { - case FormDataElement::data: { - blobData->appendBytes(element.m_data.data(), element.m_data.size()); - break; - } - case FormDataElement::encodedFile: - blobData->appendFile(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime); - break; - case FormDataElement::encodedBlob: - if (element.m_optionalBlobDataHandle) - blobData->appendBlob(element.m_optionalBlobDataHandle, 0, element.m_optionalBlobDataHandle->size()); - break; - case FormDataElement::encodedFileSystemURL: - blobData->appendFileSystemURL(element.m_fileSystemURL, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime); - break; - default: - ASSERT_NOT_REACHED(); - } - } - blobData->setContentType(AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + httpBody->boundary().data()); - const long long length = blobData->length(); - Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); - return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState); - } - ASSERT_NOT_REACHED(); - return nullptr; + return create(context, bodyHandle.release(), contentType, ResponseInit(init, exceptionState), exceptionState); } -Response* Response::create(ExecutionContext* context, Blob* body, const ResponseInit& responseInit, ExceptionState& exceptionState) +Response* Response::create(ExecutionContext* context, PassOwnPtr<FetchDataConsumerHandle> bodyHandle, const String& contentType, const ResponseInit& init, ExceptionState& exceptionState) { - unsigned short status = responseInit.status; + unsigned short status = init.status; // "1. If |init|'s status member is not in the range 200 to 599, inclusive, throw a // RangeError." if (status < 200 || 599 < status) { exceptionState.throwRangeError(ExceptionMessages::indexOutsideRange<unsigned>("status", status, 200, ExceptionMessages::InclusiveBound, 599, ExceptionMessages::InclusiveBound)); - return 0; + return nullptr; } // "2. If |init|'s statusText member does not match the Reason-Phrase // token production, throw a TypeError." - if (!isValidReasonPhrase(responseInit.statusText)) { + if (!isValidReasonPhrase(init.statusText)) { exceptionState.throwTypeError("Invalid statusText"); - return 0; + return nullptr; } // "3. Let |r| be a new Response object, associated with a new response, @@ -187,33 +151,35 @@ Response* r = new Response(context); // "4. Set |r|'s response's status to |init|'s status member." - r->m_response->setStatus(responseInit.status); + r->m_response->setStatus(init.status); // "5. Set |r|'s response's status message to |init|'s statusText member." - r->m_response->setStatusMessage(AtomicString(responseInit.statusText)); + r->m_response->setStatusMessage(AtomicString(init.statusText)); // "6. If |init|'s headers member is present, run these substeps:" - if (responseInit.headers) { + if (init.headers) { // "1. Empty |r|'s response's header list." r->m_response->headerList()->clearList(); // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow // any exceptions." - r->m_headers->fillWith(responseInit.headers.get(), exceptionState); + r->m_headers->fillWith(init.headers.get(), exceptionState); if (exceptionState.hadException()) - return 0; - } else if (!responseInit.headersDictionary.isUndefinedOrNull()) { + return nullptr; + } else if (!init.headersDictionary.isUndefinedOrNull()) { // "1. Empty |r|'s response's header list." r->m_response->headerList()->clearList(); // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow // any exceptions." - r->m_headers->fillWith(responseInit.headersDictionary, exceptionState); + r->m_headers->fillWith(init.headersDictionary, exceptionState); if (exceptionState.hadException()) - return 0; + return nullptr; } // "7. If body is given, run these substeps:" - if (body) { - // "1. If |init|'s status member is a null body status, throw a TypeError." - // "2. Let |stream| and |Content-Type| be the result of extracting body." + if (bodyHandle) { + // "1. If |init|'s status member is a null body status, throw a + // TypeError." + // "2. Let |stream| and |Content-Type| be the result of extracting + // body." // "3. Set |r|'s response's body to |stream|." // "4. If |Content-Type| is non-null and |r|'s response's header list // contains no header named `Content-Type`, append `Content-Type`/ @@ -224,11 +190,11 @@ // Content-Type to its value." if (isNullBodyStatus(status)) { exceptionState.throwTypeError("Response with null body status cannot have body"); - return 0; + return nullptr; } - r->m_response->replaceBodyStreamBuffer(new BodyStreamBuffer(FetchBlobDataConsumerHandle::create(context, body->blobDataHandle()))); - if (!body->type().isEmpty() && !r->m_response->headerList()->has("Content-Type")) - r->m_response->headerList()->append("Content-Type", body->type()); + r->m_response->replaceBodyStreamBuffer(new BodyStreamBuffer(bodyHandle)); + if (!contentType.isEmpty() && !r->m_response->headerList()->has("Content-Type")) + r->m_response->headerList()->append("Content-Type", contentType); } // "8. Set |r|'s MIME type to the result of extracting a MIME type
diff --git a/third_party/WebKit/Source/modules/fetch/Response.h b/third_party/WebKit/Source/modules/fetch/Response.h index 82b5b4a..b7433d5 100644 --- a/third_party/WebKit/Source/modules/fetch/Response.h +++ b/third_party/WebKit/Source/modules/fetch/Response.h
@@ -15,12 +15,14 @@ #include "modules/fetch/Headers.h" #include "platform/blob/BlobData.h" #include "platform/heap/Handle.h" +#include "wtf/PassOwnPtr.h" namespace blink { class Blob; class DOMArrayBuffer; class ExceptionState; +class FetchDataConsumerHandle; class ResponseInit; class WebServiceWorkerResponse; @@ -36,7 +38,7 @@ static Response* create(ExecutionContext*, ExceptionState&); static Response* create(ExecutionContext*, const BodyInit&, const Dictionary&, ExceptionState&); - static Response* create(ExecutionContext*, Blob*, const ResponseInit&, ExceptionState&); + static Response* create(ExecutionContext*, PassOwnPtr<FetchDataConsumerHandle> bodyHandle, const String& contentType, const ResponseInit&, ExceptionState&); static Response* create(ExecutionContext*, FetchResponseData*); static Response* create(ExecutionContext*, const WebServiceWorkerResponse&);
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi index 7989c0c..5a911672 100644 --- a/third_party/WebKit/Source/modules/modules.gypi +++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -842,8 +842,6 @@ 'compositorworker/CompositorWorker.h', 'compositorworker/CompositorWorkerGlobalScope.cpp', 'compositorworker/CompositorWorkerGlobalScope.h', - 'compositorworker/CompositorWorkerManager.cpp', - 'compositorworker/CompositorWorkerManager.h', 'compositorworker/CompositorWorkerMessagingProxy.cpp', 'compositorworker/CompositorWorkerMessagingProxy.h', 'compositorworker/CompositorWorkerThread.cpp', @@ -1844,7 +1842,7 @@ 'cachestorage/CacheTest.cpp', 'canvas2d/CanvasRenderingContext2DAPITest.cpp', 'canvas2d/CanvasRenderingContext2DTest.cpp', - 'compositorworker/CompositorWorkerManagerTest.cpp', + 'compositorworker/CompositorWorkerThreadTest.cpp', 'fetch/BodyStreamBufferTest.cpp', 'fetch/CompositeDataConsumerHandleTest.cpp', 'fetch/DataConsumerHandleTestUtil.cpp',
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp index 87fddec1..2e298a3a 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -1654,6 +1654,9 @@ void WebGL2RenderingContextBase::deleteQuery(WebGLQuery* query) { + if (isContextLost() || !query) + return; + if (m_currentBooleanOcclusionQuery == query) { webContext()->endQueryEXT(m_currentBooleanOcclusionQuery->getTarget()); m_currentBooleanOcclusionQuery = nullptr; @@ -1678,6 +1681,11 @@ void WebGL2RenderingContextBase::beginQuery(GLenum target, WebGLQuery* query) { bool deleted; + if (!query) { + synthesizeGLError(GL_INVALID_OPERATION, "beginQuery", "query object is null"); + return; + } + if (!checkObjectToBeBound("beginQuery", query, deleted)) return; if (deleted) {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index ac5365b..b0657c4 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1914,13 +1914,12 @@ synthesizeGLError(GL_INVALID_ENUM, "compressedTexSubImage2D", "invalid format"); return; } - if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data)) - return; - - if (!isWebGL2OrHigher() && format != tex->getInternalFormat(target, level)) { + if (format != tex->getInternalFormat(target, level)) { synthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format"); return; } + if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data)) + return; if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex)) return;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index c9a00cd..491578c9 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -83,7 +83,7 @@ GeometryInterfaces status=test GetUserMedia depends_on=MediaDevices, status=experimental GlobalCacheStorage status=stable -HiResEventTimeStamp status=experimental +HiResEventTimeStamp status=stable ImageColorProfiles ImageOrientation status=test ImageRenderingPixelated status=stable
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.h b/third_party/WebKit/Source/platform/fonts/FontDescription.h index 32f57fd..2fb85ef 100644 --- a/third_party/WebKit/Source/platform/fonts/FontDescription.h +++ b/third_party/WebKit/Source/platform/fonts/FontDescription.h
@@ -35,6 +35,7 @@ #include "platform/fonts/FontWidthVariant.h" #include "platform/fonts/TextRenderingMode.h" #include "platform/fonts/TypesettingFeatures.h" +#include "platform/text/LocaleToScriptMapping.h" #include "wtf/Allocator.h" #include "wtf/MathExtras.h" @@ -206,8 +207,11 @@ void setTextRendering(TextRenderingMode rendering) { m_fields.m_textRendering = rendering; updateTypesettingFeatures(); } void setOrientation(FontOrientation orientation) { m_fields.m_orientation = static_cast<unsigned>(orientation); } void setWidthVariant(FontWidthVariant widthVariant) { m_fields.m_widthVariant = widthVariant; } - void setScript(UScriptCode s) { m_fields.m_script = s; } - void setLocale(const AtomicString& locale) { m_locale = locale; } + void setLocale(const AtomicString& locale) + { + m_locale = locale; + m_fields.m_script = localeToScriptCodeForFontSelection(locale); + } void setSyntheticBold(bool syntheticBold) { m_fields.m_syntheticBold = syntheticBold; } void setSyntheticItalic(bool syntheticItalic) { m_fields.m_syntheticItalic = syntheticItalic; } void setFeatureSettings(PassRefPtr<FontFeatureSettings> settings) { m_featureSettings = settings; }
diff --git a/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp b/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp index 02a808a..be05c2a0 100644 --- a/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp
@@ -17,7 +17,8 @@ const UChar32 testChar = 228; FontDescription fontDescription; - fontDescription.setScript(USCRIPT_SIMPLIFIED_HAN); + fontDescription.setLocale("zh"); + ASSERT_EQ(USCRIPT_SIMPLIFIED_HAN, fontDescription.script()); fontDescription.setGenericFamily(FontDescription::StandardFamily); FontCache* fontCache = FontCache::fontCache();
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp index ce9d7362..60bae9d 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
@@ -18,7 +18,8 @@ void SetUp() override { fontDescription.setComputedSize(12.0); - fontDescription.setScript(USCRIPT_LATIN); + fontDescription.setLocale("en"); + ASSERT_EQ(USCRIPT_LATIN, fontDescription.script()); fontDescription.setGenericFamily(FontDescription::StandardFamily); font = Font(fontDescription);
diff --git a/third_party/WebKit/Source/platform/graphics/Path.cpp b/third_party/WebKit/Source/platform/graphics/Path.cpp index 9cccb49..b23f1aa 100644 --- a/third_party/WebKit/Source/platform/graphics/Path.cpp +++ b/third_party/WebKit/Source/platform/graphics/Path.cpp
@@ -142,14 +142,26 @@ pathElement.type = PathElementAddCurveToPoint; pathElement.points = convertPathPoints(pathPoints, &pts[1], 3); break; + case SkPath::kConic_Verb: { + // Approximate with quads. Use two for now, increase if more precision is needed. + const int kPow2 = 1; + const unsigned quadCount = 1 << kPow2; + SkPoint quads[1 + 2 * quadCount]; + SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, kPow2); + + pathElement.type = PathElementAddQuadCurveToPoint; + for (unsigned i = 0; i < quadCount; ++i) { + pathElement.points = convertPathPoints(pathPoints, &quads[1 + 2 * i], 2); + function(info, &pathElement); + } + continue; + } case SkPath::kClose_Verb: pathElement.type = PathElementCloseSubpath; pathElement.points = convertPathPoints(pathPoints, 0, 0); break; case SkPath::kDone_Verb: return; - default: // place-holder for kConic_Verb, when that lands from skia - break; } function(info, &pathElement); } @@ -357,7 +369,8 @@ void Path::addRect(const FloatRect& rect) { - m_path.addRect(rect); + // Start at upper-left, add clock-wise. + m_path.addRect(rect, SkPath::kCW_Direction, 0); } void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float rotation, float startAngle, float endAngle, bool anticlockwise) @@ -382,7 +395,8 @@ void Path::addEllipse(const FloatRect& rect) { - m_path.addOval(rect); + // Start at 3 o'clock, add clock-wise. + m_path.addOval(rect, SkPath::kCW_Direction, 1); } void Path::addRoundedRect(const FloatRoundedRect& r) @@ -441,39 +455,10 @@ void Path::addPathForRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius) { - addBeziersForRoundedRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); -} - -// Approximation of control point positions on a bezier to simulate a quarter of a circle. -// This is 1-kappa, where kappa = 4 * (sqrt(2) - 1) / 3 -static const float gCircleControlPoint = 0.447715f; - -void Path::addBeziersForRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius) -{ - moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y())); - - addLineTo(FloatPoint(rect.maxX() - topRightRadius.width(), rect.y())); - if (topRightRadius.width() > 0 || topRightRadius.height() > 0) - addBezierCurveTo(FloatPoint(rect.maxX() - topRightRadius.width() * gCircleControlPoint, rect.y()), - FloatPoint(rect.maxX(), rect.y() + topRightRadius.height() * gCircleControlPoint), - FloatPoint(rect.maxX(), rect.y() + topRightRadius.height())); - addLineTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius.height())); - if (bottomRightRadius.width() > 0 || bottomRightRadius.height() > 0) - addBezierCurveTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius.height() * gCircleControlPoint), - FloatPoint(rect.maxX() - bottomRightRadius.width() * gCircleControlPoint, rect.maxY()), - FloatPoint(rect.maxX() - bottomRightRadius.width(), rect.maxY())); - addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.maxY())); - if (bottomLeftRadius.width() > 0 || bottomLeftRadius.height() > 0) - addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircleControlPoint, rect.maxY()), - FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height() * gCircleControlPoint), - FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height())); - addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height())); - if (topLeftRadius.width() > 0 || topLeftRadius.height() > 0) - addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint), - FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, rect.y()), - FloatPoint(rect.x() + topLeftRadius.width(), rect.y())); - - closeSubpath(); + // Start at upper-left (after corner radii), add clock-wise. + m_path.addRRect( + FloatRoundedRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius), + SkPath::kCW_Direction, 0); } void Path::addPath(const Path& src, const AffineTransform& transform)
diff --git a/third_party/WebKit/Source/platform/graphics/Path.h b/third_party/WebKit/Source/platform/graphics/Path.h index adcacae..5c5679ae 100644 --- a/third_party/WebKit/Source/platform/graphics/Path.h +++ b/third_party/WebKit/Source/platform/graphics/Path.h
@@ -143,7 +143,6 @@ void transform(const AffineTransform&); void addPathForRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); - void addBeziersForRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); bool subtractPath(const Path&);
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp index 8939238..c4ea220 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -112,6 +112,11 @@ return m_config.compositorSupport; } +WebUnitTestSupport* TestingPlatformSupport::unitTestSupport() +{ + return m_oldPlatform ? m_oldPlatform->unitTestSupport() : nullptr; +} + WebThread* TestingPlatformSupport::currentThread() { return m_oldPlatform ? m_oldPlatform->currentThread() : nullptr;
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h index e1d5a49e..e028e33 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -80,6 +80,7 @@ WebString defaultLocale() override; WebCompositorSupport* compositorSupport() override; WebThread* currentThread() override; + WebUnitTestSupport* unitTestSupport() override; protected: const Config m_config;
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.cpp b/third_party/WebKit/Source/platform/weborigin/KURL.cpp index 99af364..c430db07 100644 --- a/third_party/WebKit/Source/platform/weborigin/KURL.cpp +++ b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
@@ -186,6 +186,17 @@ return *this == blankURL(); } +const KURL& srcdocURL() +{ + DEFINE_STATIC_LOCAL(KURL, staticSrcdocURL, (ParsedURLString, "about:srcdoc")); + return staticSrcdocURL; +} + +bool KURL::isAboutSrcdocURL() const +{ + return *this == srcdocURL(); +} + String KURL::elidedString() const { if (string().length() <= 1024)
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.h b/third_party/WebKit/Source/platform/weborigin/KURL.h index d6fcb7b3..14668c4 100644 --- a/third_party/WebKit/Source/platform/weborigin/KURL.h +++ b/third_party/WebKit/Source/platform/weborigin/KURL.h
@@ -138,6 +138,7 @@ bool protocolIsInHTTPFamily() const; bool isLocalFile() const; bool isAboutBlankURL() const; // Is exactly about:blank. + bool isAboutSrcdocURL() const; // Is exactly about:srcdoc. bool setProtocol(const String&); void setHost(const String&); @@ -212,6 +213,7 @@ PLATFORM_EXPORT bool equalIgnoringFragmentIdentifier(const KURL&, const KURL&); PLATFORM_EXPORT const KURL& blankURL(); +PLATFORM_EXPORT const KURL& srcdocURL(); // Functions to do URL operations on strings. // These are operations that aren't faster on a parsed URL.
diff --git a/third_party/WebKit/Source/web/WebElement.cpp b/third_party/WebKit/Source/web/WebElement.cpp index 0fada19a..b365a2cc 100644 --- a/third_party/WebKit/Source/web/WebElement.cpp +++ b/third_party/WebKit/Source/web/WebElement.cpp
@@ -146,9 +146,9 @@ return constUnwrap<Element>()->hasNonEmptyLayoutSize(); } -WebRect WebElement::boundsInViewportSpace() +WebRect WebElement::boundsInViewport() { - return unwrap<Element>()->boundsInViewportSpace(); + return unwrap<Element>()->boundsInViewport(); } WebImage WebElement::imageContents()
diff --git a/third_party/WebKit/Source/web/WebMetaElement.cpp b/third_party/WebKit/Source/web/WebMetaElement.cpp new file mode 100644 index 0000000..34b9c26 --- /dev/null +++ b/third_party/WebKit/Source/web/WebMetaElement.cpp
@@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "public/web/WebMetaElement.h" + +#include "core/HTMLNames.h" +#include "core/html/HTMLMetaElement.h" +#include "public/platform/WebString.h" +#include "wtf/PassRefPtr.h" + +namespace blink { + +WebString WebMetaElement::computeEncoding() const +{ + return String(constUnwrap<HTMLMetaElement>()->computeEncoding().name()); +} + +WebMetaElement::WebMetaElement(const PassRefPtrWillBeRawPtr<HTMLMetaElement>& element) + : WebElement(element) +{ +} + +DEFINE_WEB_NODE_TYPE_CASTS(WebMetaElement, isHTMLMetaElement(constUnwrap<Node>())); + +WebMetaElement& WebMetaElement::operator=(const PassRefPtrWillBeRawPtr<HTMLMetaElement>& element) +{ + m_private = element; + return *this; +} + +WebMetaElement::operator PassRefPtrWillBeRawPtr<HTMLMetaElement>() const +{ + return toHTMLMetaElement(m_private.get()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp b/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp index 694c823..e76398e 100644 --- a/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp +++ b/third_party/WebKit/Source/web/WebPageSerializerImpl.cpp
@@ -131,7 +131,7 @@ // have overrided the META which have correct charset declaration after // serializing open tag of HEAD element. ASSERT(element); - if (isCharsetSpecifyingNode(*element)) { + if (isHTMLMetaElement(element) && toHTMLMetaElement(element)->computeEncoding().isValid()) { // Found META tag declared charset, we need to skip it when // serializing DOM. param->skipMetaElement = element;
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp index 3e54d0f..f8b1a92 100644 --- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp +++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -1398,11 +1398,15 @@ visualViewport.setScale(2); visualViewport.setLocation(scrollDelta); - IntRect boundsInViewport = inputElement->boundsInViewportSpace(); + const IntRect boundsInViewport = inputElement->boundsInViewport(); + IntRect expectedBounds = bounds; + expectedBounds.scale(2.f); + IntPoint expectedScrollDelta = scrollDelta; + expectedScrollDelta.scale(2.f, 2.f); - EXPECT_POINT_EQ(IntPoint(bounds.location() - scrollDelta), + EXPECT_POINT_EQ(IntPoint(expectedBounds.location() - expectedScrollDelta), boundsInViewport.location()); - EXPECT_SIZE_EQ(bounds.size(), boundsInViewport.size()); + EXPECT_SIZE_EQ(expectedBounds.size(), boundsInViewport.size()); } // Tests that when a new frame is created, it is created with the intended
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index d1965ce7..a2e5930a 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4128,7 +4128,7 @@ static WebRect elementBounds(WebFrame* frame, const WebString& id) { - return frame->document().getElementById(id).boundsInViewportSpace(); + return frame->document().getElementById(id).boundsInViewport(); } static std::string selectionAsString(WebFrame* frame)
diff --git a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp index fd21b8ab..c7b87e5 100644 --- a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
@@ -32,112 +32,79 @@ #include "public/web/WebPageSerializer.h" #include "platform/testing/URLTestHelpers.h" +#include "platform/weborigin/KURL.h" #include "public/platform/Platform.h" #include "public/platform/WebString.h" #include "public/platform/WebURL.h" -#include "public/platform/WebURLRequest.h" -#include "public/platform/WebURLResponse.h" #include "public/platform/WebUnitTestSupport.h" -#include "public/web/WebDocument.h" -#include "public/web/WebFrame.h" #include "public/web/WebPageSerializerClient.h" -#include "public/web/WebView.h" #include "testing/gtest/include/gtest/gtest.h" +#include "web/WebLocalFrameImpl.h" +#include "web/WebViewImpl.h" #include "web/tests/FrameTestHelpers.h" - -using blink::Document; -using blink::URLTestHelpers::toKURL; +#include "wtf/text/StringBuilder.h" namespace blink { namespace { -class SimpleWebPageSerializerClient : public WebPageSerializerClient { +class SimpleWebPageSerializerClient final : public WebPageSerializerClient { public: - std::string toString() const { return m_string; } + String toString() { return m_builder.toString(); } private: void didSerializeDataForFrame(const WebCString& data, PageSerializationStatus) final { - m_string += data; + m_builder.append(data.data(), data.length()); } - std::string m_string; + StringBuilder m_builder; }; } // namespace class WebPageSerializerTest : public testing::Test { -public: - WebPageSerializerTest() - : m_supportedSchemes(static_cast<size_t>(3)) - { - m_supportedSchemes[0] = "http"; - m_supportedSchemes[1] = "https"; - m_supportedSchemes[2] = "file"; - - registerMockedImageURL("http://www.test.com/awesome.png"); - } - protected: - void SetUp() override + WebPageSerializerTest() { m_helper.initialize(); } - void TearDown() override + ~WebPageSerializerTest() override { Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); } - void registerMockedURLLoad(const std::string& url, const WebString& fileName) - { - URLTestHelpers::registerMockedURLLoad(toKURL(url), fileName, WebString::fromUTF8("pageserialization/"), WebString::fromUTF8("text/html")); - } - - void registerMockedImageURL(const std::string& url) + void registerMockedImageURL(const String& url) { // Image resources need to be mocked, but irrelevant here what image they map to. - URLTestHelpers::registerMockedURLLoad(toKURL(url), "pageserialization/awesome.png"); + URLTestHelpers::registerMockedURLLoad(KURL(ParsedURLString, url), "pageserialization/awesome.png"); } - void loadURLInTopFrame(const WebURL& url) + String serializeFile(const String& url, const String& fileName) { - FrameTestHelpers::loadFrame(m_helper.webView()->mainFrame(), url.string().utf8()); + KURL parsedURL(ParsedURLString, url); + URLTestHelpers::registerMockedURLLoad(parsedURL, fileName, "pageserialization/", "text/html"); + FrameTestHelpers::loadFrame(mainFrameImpl(), url.utf8().data()); + WebVector<WebURL> links(&parsedURL, 1); + WebVector<WebString> localPaths(&"local", 1); + SimpleWebPageSerializerClient serializerClient; + WebPageSerializer::serialize(mainFrameImpl(), &serializerClient, links, localPaths, ""); + return serializerClient.toString(); } - static bool webVectorContains(const WebVector<WebURL>& vector, const char* url) + WebLocalFrameImpl* mainFrameImpl() { - return vector.contains(WebURL(toKURL(std::string(url)))); + return m_helper.webViewImpl()->mainFrameImpl(); } - // Useful for debugging. - static void printWebURLs(const WebVector<WebURL>& urls) - { - for (size_t i = 0; i < urls.size(); i++) - printf("%s\n", urls[i].spec().data()); - } - - WebView* webView() const { return m_helper.webView(); } - - WebVector<WebCString> m_supportedSchemes; - private: FrameTestHelpers::WebViewHelper m_helper; }; TEST_F(WebPageSerializerTest, URLAttributeValues) { - WebURL topFrameURL = toKURL("http://www.test.com"); - registerMockedURLLoad(topFrameURL.spec(), WebString::fromUTF8("url_attribute_values.html")); registerMockedImageURL("javascript:\""); - loadURLInTopFrame(topFrameURL); - - SimpleWebPageSerializerClient serializerClient; - WebVector<WebURL> links(&topFrameURL, 1); - WebVector<WebString> localPaths(&"local", 1); - WebPageSerializer::serialize(webView()->mainFrame()->toWebLocalFrame(), &serializerClient, links, localPaths, ""); - const char* expectedHTML = "\n<!-- saved from url=(0020)http://www.test.com/ -->\n" "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" @@ -145,21 +112,12 @@ "<a href=\"http://www.test.com/local#"\">local</a>\n" "<a href=\"http://www.example.com/#"><script>alert(0)</script>\">external</a>\n" "</body></html>"; - EXPECT_EQ(expectedHTML, serializerClient.toString()); + String actualHTML = serializeFile("http://www.test.com", "url_attribute_values.html"); + EXPECT_EQ(expectedHTML, actualHTML); } TEST_F(WebPageSerializerTest, EncodingAndNormalization) { - WebURL topFrameURL = toKURL("http://www.test.com"); - registerMockedURLLoad(topFrameURL.spec(), WebString::fromUTF8("encoding_normalization.html")); - - loadURLInTopFrame(topFrameURL); - - SimpleWebPageSerializerClient serializerClient; - WebVector<WebURL> links(&topFrameURL, 1); - WebVector<WebString> localPaths(&"local", 1); - WebPageSerializer::serialize(webView()->mainFrame()->toWebLocalFrame(), &serializerClient, links, localPaths, ""); - const char* expectedHTML = "<!DOCTYPE html>\n" "<!-- saved from url=(0020)http://www.test.com/ -->\n" @@ -168,21 +126,14 @@ "</head><body>\n" "\xe4\xc5\xd1\xe2\n" "\n</body></html>"; - EXPECT_EQ(expectedHTML, serializerClient.toString()); + String actualHTML = serializeFile("http://www.test.com", "encoding_normalization.html"); + EXPECT_EQ(expectedHTML, actualHTML); } -TEST_F(WebPageSerializerTest, fromUrlWithMinusMinus) +TEST_F(WebPageSerializerTest, FromUrlWithMinusMinus) { - WebURL topFrameURL = toKURL("http://www.test.com?--x--"); - registerMockedURLLoad(topFrameURL.spec(), WebString::fromUTF8("text_only_page.html")); - loadURLInTopFrame(topFrameURL); - - SimpleWebPageSerializerClient serializerClient; - WebVector<WebURL> links(&topFrameURL, 1); - WebVector<WebString> localPaths(&"local", 1); - WebPageSerializer::serialize(webView()->mainFrame()->toWebLocalFrame(), &serializerClient, links, localPaths, ""); - - EXPECT_EQ("<!-- saved from url=(0030)http://www.test.com/?-%2Dx-%2D -->", serializerClient.toString().substr(1, 60)); + String actualHTML = serializeFile("http://www.test.com?--x--", "text_only_page.html"); + EXPECT_EQ("<!-- saved from url=(0030)http://www.test.com/?-%2Dx-%2D -->", actualHTML.substring(1, 60)); } } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp index abe1920..62554c7 100644 --- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -368,7 +368,7 @@ EXPECT_EQ(WebInputEvent::Undefined, testPlugin->getLastInputEventType()); // Next, send an event that does hit the plugin, and verify it does receive it. - WebRect rect = pluginContainerOneElement.boundsInViewportSpace(); + WebRect rect = pluginContainerOneElement.boundsInViewport(); event.x = rect.x + rect.width / 2; event.y = rect.y + rect.height / 2; @@ -395,7 +395,7 @@ toWebPluginContainerImpl(getWebPluginContainer(webView, WebString::fromUTF8("translated-plugin"))); pluginContainerImpl->setFrameRect(IntRect(0, 0, 300, 300)); - WebRect rect = pluginContainerImpl->element().boundsInViewportSpace(); + WebRect rect = pluginContainerImpl->element().boundsInViewport(); EXPECT_TRUE(pluginContainerImpl->isRectTopmost(rect)); // Cause the plugin's frame to be detached.
diff --git a/third_party/WebKit/Source/web/web.gypi b/third_party/WebKit/Source/web/web.gypi index eee6c0f2..bcbc134 100644 --- a/third_party/WebKit/Source/web/web.gypi +++ b/third_party/WebKit/Source/web/web.gypi
@@ -176,6 +176,7 @@ 'WebMIDIPermissionRequest.cpp', 'WebMediaDevicesRequest.cpp', 'WebMediaStreamRegistry.cpp', + 'WebMetaElement.cpp', 'WebNetworkStateNotifier.cpp', 'WebNode.cpp', 'WebOptionElement.cpp',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py index 7024d07..2e4584bb2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -1105,7 +1105,6 @@ clean_env['DISPLAY'] = self._value_or_default_from_environ('DISPLAY', ':1') if self.host.platform.is_mac(): clean_env['DYLD_LIBRARY_PATH'] = self._build_path() - clean_env['DYLD_FRAMEWORK_PATH'] = self._build_path() variables_to_copy += [ 'HOME', ]
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi index b231d11..6cf6a0e1 100644 --- a/third_party/WebKit/public/blink_headers.gypi +++ b/third_party/WebKit/public/blink_headers.gypi
@@ -418,6 +418,7 @@ "web/WebMediaPlayerAction.h", "web/WebMediaStreamRegistry.h", "web/WebMenuItemInfo.h", + "web/WebMetaElement.h", "web/WebNavigationPolicy.h", "web/WebNavigationType.h", "web/WebNavigatorContentUtilsClient.h",
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h index 851d68f7..1703be68 100644 --- a/third_party/WebKit/public/platform/Platform.h +++ b/third_party/WebKit/public/platform/Platform.h
@@ -434,6 +434,10 @@ // Returns an interface to the main thread. Can be null if blink was initialized on a thread without a message loop. BLINK_PLATFORM_EXPORT WebThread* mainThread() const; + // Returns an interface to the compositor thread. This can be null if the + // renderer was created with threaded rendering desabled. + virtual WebThread* compositorThread() const { return 0; } + // Vibration ----------------------------------------------------------- // Starts a vibration for the given duration in milliseconds. If there is currently an active
diff --git a/third_party/WebKit/public/web/WebElement.h b/third_party/WebKit/public/web/WebElement.h index ae356e5..7ea6bdc5 100644 --- a/third_party/WebKit/public/web/WebElement.h +++ b/third_party/WebKit/public/web/WebElement.h
@@ -70,11 +70,10 @@ // If this element takes up space in the layout of the page. BLINK_EXPORT bool hasNonEmptyLayoutSize() const; - // Returns the bounds of the element in viewport space. The bounds - // have been adjusted to include any transformations. This view is - // also called the Root View in Blink. + // Returns the bounds of the element in Visual Viewport. The bounds + // have been adjusted to include any transformations, including page scale. // This function will update the layout if required. - BLINK_EXPORT WebRect boundsInViewportSpace(); + BLINK_EXPORT WebRect boundsInViewport(); // Returns the image contents of this element or a null WebImage // if there isn't any.
diff --git a/third_party/WebKit/public/web/WebMetaElement.h b/third_party/WebKit/public/web/WebMetaElement.h new file mode 100644 index 0000000..827c3f6 --- /dev/null +++ b/third_party/WebKit/public/web/WebMetaElement.h
@@ -0,0 +1,39 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WebMetaElement_h +#define WebMetaElement_h + +#include "WebElement.h" + +namespace blink { + +class HTMLMetaElement; + +class WebMetaElement final : public WebElement { +public: + WebMetaElement() : WebElement() { } + WebMetaElement(const WebMetaElement& element) : WebElement(element) { } + + WebMetaElement& operator=(const WebMetaElement& element) + { + WebElement::assign(element); + return *this; + } + void assign(const WebMetaElement& element) { WebElement::assign(element); } + + BLINK_EXPORT WebString computeEncoding() const; + +#if BLINK_IMPLEMENTATION + WebMetaElement(const PassRefPtrWillBeRawPtr<HTMLMetaElement>&); + WebMetaElement& operator=(const PassRefPtrWillBeRawPtr<HTMLMetaElement>&); + operator PassRefPtrWillBeRawPtr<HTMLMetaElement>() const; +#endif +}; + +DECLARE_WEB_NODE_TYPE_CASTS(WebMetaElement); + +} // namespace blink + +#endif
diff --git a/third_party/chaijs/LICENSE b/third_party/chaijs/LICENSE new file mode 100644 index 0000000..74bffb9 --- /dev/null +++ b/third_party/chaijs/LICENSE
@@ -0,0 +1,9 @@ +(Copied from https://github.com/chaijs/chai/blob/master/README.md). +-------------------------------------------------------------------------------- +Copyright (c) 2011-2015 Jake Luer jake@alogicalparadox.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/chaijs/OWNERS b/third_party/chaijs/OWNERS new file mode 100644 index 0000000..bfc58994 --- /dev/null +++ b/third_party/chaijs/OWNERS
@@ -0,0 +1,2 @@ +dpapad@chromium.org +dbeam@chromium.org
diff --git a/third_party/chaijs/README.chromium b/third_party/chaijs/README.chromium new file mode 100644 index 0000000..06eaf936 --- /dev/null +++ b/third_party/chaijs/README.chromium
@@ -0,0 +1,16 @@ +Name: Chai Assertion Library +Short Name: chai +URL: https://github.com/chaijs/chai +Version: 3.4.1 +Revision: 12bfdd17648e2b3e11d64e5b926007a6d84bfbe8 +Date: Mon Nov 23 17:06:02 2015 +0000 +License: MIT +License File: NOT_SHIPPED +Security Critical: no + +Description: +BDD / TDD assertion framework for node.js and the browser that can be +paired with any testing framework. + +Local Modifications: +Copied license text out of README.md.
diff --git a/third_party/chaijs/chai.js b/third_party/chaijs/chai.js new file mode 100644 index 0000000..431fea3 --- /dev/null +++ b/third_party/chaijs/chai.js
@@ -0,0 +1,5873 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +module.exports = require('./lib/chai'); + +},{"./lib/chai":2}],2:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var used = [] + , exports = module.exports = {}; + +/*! + * Chai version + */ + +exports.version = '3.4.1'; + +/*! + * Assertion Error + */ + +exports.AssertionError = require('assertion-error'); + +/*! + * Utils for plugins (not exported) + */ + +var util = require('./chai/utils'); + +/** + * # .use(function) + * + * Provides a way to extend the internals of Chai + * + * @param {Function} + * @returns {this} for chaining + * @api public + */ + +exports.use = function (fn) { + if (!~used.indexOf(fn)) { + fn(this, util); + used.push(fn); + } + + return this; +}; + +/*! + * Utility Functions + */ + +exports.util = util; + +/*! + * Configuration + */ + +var config = require('./chai/config'); +exports.config = config; + +/*! + * Primary `Assertion` prototype + */ + +var assertion = require('./chai/assertion'); +exports.use(assertion); + +/*! + * Core Assertions + */ + +var core = require('./chai/core/assertions'); +exports.use(core); + +/*! + * Expect interface + */ + +var expect = require('./chai/interface/expect'); +exports.use(expect); + +/*! + * Should interface + */ + +var should = require('./chai/interface/should'); +exports.use(should); + +/*! + * Assert interface + */ + +var assert = require('./chai/interface/assert'); +exports.use(assert); + +},{"./chai/assertion":3,"./chai/config":4,"./chai/core/assertions":5,"./chai/interface/assert":6,"./chai/interface/expect":7,"./chai/interface/should":8,"./chai/utils":22,"assertion-error":30}],3:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var config = require('./config'); + +module.exports = function (_chai, util) { + /*! + * Module dependencies. + */ + + var AssertionError = _chai.AssertionError + , flag = util.flag; + + /*! + * Module export. + */ + + _chai.Assertion = Assertion; + + /*! + * Assertion Constructor + * + * Creates object for chaining. + * + * @api private + */ + + function Assertion (obj, msg, stack) { + flag(this, 'ssfi', stack || arguments.callee); + flag(this, 'object', obj); + flag(this, 'message', msg); + } + + Object.defineProperty(Assertion, 'includeStack', { + get: function() { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + return config.includeStack; + }, + set: function(value) { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + config.includeStack = value; + } + }); + + Object.defineProperty(Assertion, 'showDiff', { + get: function() { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + return config.showDiff; + }, + set: function(value) { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + config.showDiff = value; + } + }); + + Assertion.addProperty = function (name, fn) { + util.addProperty(this.prototype, name, fn); + }; + + Assertion.addMethod = function (name, fn) { + util.addMethod(this.prototype, name, fn); + }; + + Assertion.addChainableMethod = function (name, fn, chainingBehavior) { + util.addChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + Assertion.overwriteProperty = function (name, fn) { + util.overwriteProperty(this.prototype, name, fn); + }; + + Assertion.overwriteMethod = function (name, fn) { + util.overwriteMethod(this.prototype, name, fn); + }; + + Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { + util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + /** + * ### .assert(expression, message, negateMessage, expected, actual, showDiff) + * + * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. + * + * @name assert + * @param {Philosophical} expression to be tested + * @param {String|Function} message or function that returns message to display if expression fails + * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails + * @param {Mixed} expected value (remember to check for negation) + * @param {Mixed} actual (optional) will default to `this.obj` + * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails + * @api private + */ + + Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { + var ok = util.test(this, arguments); + if (true !== showDiff) showDiff = false; + if (true !== config.showDiff) showDiff = false; + + if (!ok) { + var msg = util.getMessage(this, arguments) + , actual = util.getActual(this, arguments); + throw new AssertionError(msg, { + actual: actual + , expected: expected + , showDiff: showDiff + }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); + } + }; + + /*! + * ### ._obj + * + * Quick reference to stored `actual` value for plugin developers. + * + * @api private + */ + + Object.defineProperty(Assertion.prototype, '_obj', + { get: function () { + return flag(this, 'object'); + } + , set: function (val) { + flag(this, 'object', val); + } + }); +}; + +},{"./config":4}],4:[function(require,module,exports){ +module.exports = { + + /** + * ### config.includeStack + * + * User configurable property, influences whether stack trace + * is included in Assertion error message. Default of false + * suppresses stack trace in the error message. + * + * chai.config.includeStack = true; // enable stack on error + * + * @param {Boolean} + * @api public + */ + + includeStack: false, + + /** + * ### config.showDiff + * + * User configurable property, influences whether or not + * the `showDiff` flag should be included in the thrown + * AssertionErrors. `false` will always be `false`; `true` + * will be true when the assertion has requested a diff + * be shown. + * + * @param {Boolean} + * @api public + */ + + showDiff: true, + + /** + * ### config.truncateThreshold + * + * User configurable property, sets length threshold for actual and + * expected values in assertion errors. If this threshold is exceeded, for + * example for large data structures, the value is replaced with something + * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. + * + * Set it to zero if you want to disable truncating altogether. + * + * This is especially userful when doing assertions on arrays: having this + * set to a reasonable large value makes the failure messages readily + * inspectable. + * + * chai.config.truncateThreshold = 0; // disable truncating + * + * @param {Number} + * @api public + */ + + truncateThreshold: 40 + +}; + +},{}],5:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +module.exports = function (chai, _) { + var Assertion = chai.Assertion + , toString = Object.prototype.toString + , flag = _.flag; + + /** + * ### Language Chains + * + * The following are provided as chainable getters to + * improve the readability of your assertions. They + * do not provide testing capabilities unless they + * have been overwritten by a plugin. + * + * **Chains** + * + * - to + * - be + * - been + * - is + * - that + * - which + * - and + * - has + * - have + * - with + * - at + * - of + * - same + * + * @name language chains + * @api public + */ + + [ 'to', 'be', 'been' + , 'is', 'and', 'has', 'have' + , 'with', 'that', 'which', 'at' + , 'of', 'same' ].forEach(function (chain) { + Assertion.addProperty(chain, function () { + return this; + }); + }); + + /** + * ### .not + * + * Negates any of assertions following in the chain. + * + * expect(foo).to.not.equal('bar'); + * expect(goodFn).to.not.throw(Error); + * expect({ foo: 'baz' }).to.have.property('foo') + * .and.not.equal('bar'); + * + * @name not + * @api public + */ + + Assertion.addProperty('not', function () { + flag(this, 'negate', true); + }); + + /** + * ### .deep + * + * Sets the `deep` flag, later used by the `equal` and + * `property` assertions. + * + * expect(foo).to.deep.equal({ bar: 'baz' }); + * expect({ foo: { bar: { baz: 'quux' } } }) + * .to.have.deep.property('foo.bar.baz', 'quux'); + * + * `.deep.property` special characters can be escaped + * by adding two slashes before the `.` or `[]`. + * + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name deep + * @api public + */ + + Assertion.addProperty('deep', function () { + flag(this, 'deep', true); + }); + + /** + * ### .any + * + * Sets the `any` flag, (opposite of the `all` flag) + * later used in the `keys` assertion. + * + * expect(foo).to.have.any.keys('bar', 'baz'); + * + * @name any + * @api public + */ + + Assertion.addProperty('any', function () { + flag(this, 'any', true); + flag(this, 'all', false) + }); + + + /** + * ### .all + * + * Sets the `all` flag (opposite of the `any` flag) + * later used by the `keys` assertion. + * + * expect(foo).to.have.all.keys('bar', 'baz'); + * + * @name all + * @api public + */ + + Assertion.addProperty('all', function () { + flag(this, 'all', true); + flag(this, 'any', false); + }); + + /** + * ### .a(type) + * + * The `a` and `an` assertions are aliases that can be + * used either as language chains or to assert a value's + * type. + * + * // typeof + * expect('test').to.be.a('string'); + * expect({ foo: 'bar' }).to.be.an('object'); + * expect(null).to.be.a('null'); + * expect(undefined).to.be.an('undefined'); + * expect(new Error).to.be.an('error'); + * expect(new Promise).to.be.a('promise'); + * expect(new Float32Array()).to.be.a('float32array'); + * expect(Symbol()).to.be.a('symbol'); + * + * // es6 overrides + * expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); + * + * // language chain + * expect(foo).to.be.an.instanceof(Foo); + * + * @name a + * @alias an + * @param {String} type + * @param {String} message _optional_ + * @api public + */ + + function an (type, msg) { + if (msg) flag(this, 'message', msg); + type = type.toLowerCase(); + var obj = flag(this, 'object') + , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; + + this.assert( + type === _.type(obj) + , 'expected #{this} to be ' + article + type + , 'expected #{this} not to be ' + article + type + ); + } + + Assertion.addChainableMethod('an', an); + Assertion.addChainableMethod('a', an); + + /** + * ### .include(value) + * + * The `include` and `contain` assertions can be used as either property + * based language chains or as methods to assert the inclusion of an object + * in an array or a substring in a string. When used as language chains, + * they toggle the `contains` flag for the `keys` assertion. + * + * expect([1,2,3]).to.include(2); + * expect('foobar').to.contain('foo'); + * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); + * + * @name include + * @alias contain + * @alias includes + * @alias contains + * @param {Object|String|Number} obj + * @param {String} message _optional_ + * @api public + */ + + function includeChainingBehavior () { + flag(this, 'contains', true); + } + + function include (val, msg) { + _.expectTypes(this, ['array', 'object', 'string']); + + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var expected = false; + + if (_.type(obj) === 'array' && _.type(val) === 'object') { + for (var i in obj) { + if (_.eql(obj[i], val)) { + expected = true; + break; + } + } + } else if (_.type(val) === 'object') { + if (!flag(this, 'negate')) { + for (var k in val) new Assertion(obj).property(k, val[k]); + return; + } + var subset = {}; + for (var k in val) subset[k] = obj[k]; + expected = _.eql(subset, val); + } else { + expected = (obj != undefined) && ~obj.indexOf(val); + } + this.assert( + expected + , 'expected #{this} to include ' + _.inspect(val) + , 'expected #{this} to not include ' + _.inspect(val)); + } + + Assertion.addChainableMethod('include', include, includeChainingBehavior); + Assertion.addChainableMethod('contain', include, includeChainingBehavior); + Assertion.addChainableMethod('contains', include, includeChainingBehavior); + Assertion.addChainableMethod('includes', include, includeChainingBehavior); + + /** + * ### .ok + * + * Asserts that the target is truthy. + * + * expect('everything').to.be.ok; + * expect(1).to.be.ok; + * expect(false).to.not.be.ok; + * expect(undefined).to.not.be.ok; + * expect(null).to.not.be.ok; + * + * @name ok + * @api public + */ + + Assertion.addProperty('ok', function () { + this.assert( + flag(this, 'object') + , 'expected #{this} to be truthy' + , 'expected #{this} to be falsy'); + }); + + /** + * ### .true + * + * Asserts that the target is `true`. + * + * expect(true).to.be.true; + * expect(1).to.not.be.true; + * + * @name true + * @api public + */ + + Assertion.addProperty('true', function () { + this.assert( + true === flag(this, 'object') + , 'expected #{this} to be true' + , 'expected #{this} to be false' + , this.negate ? false : true + ); + }); + + /** + * ### .false + * + * Asserts that the target is `false`. + * + * expect(false).to.be.false; + * expect(0).to.not.be.false; + * + * @name false + * @api public + */ + + Assertion.addProperty('false', function () { + this.assert( + false === flag(this, 'object') + , 'expected #{this} to be false' + , 'expected #{this} to be true' + , this.negate ? true : false + ); + }); + + /** + * ### .null + * + * Asserts that the target is `null`. + * + * expect(null).to.be.null; + * expect(undefined).to.not.be.null; + * + * @name null + * @api public + */ + + Assertion.addProperty('null', function () { + this.assert( + null === flag(this, 'object') + , 'expected #{this} to be null' + , 'expected #{this} not to be null' + ); + }); + + /** + * ### .undefined + * + * Asserts that the target is `undefined`. + * + * expect(undefined).to.be.undefined; + * expect(null).to.not.be.undefined; + * + * @name undefined + * @api public + */ + + Assertion.addProperty('undefined', function () { + this.assert( + undefined === flag(this, 'object') + , 'expected #{this} to be undefined' + , 'expected #{this} not to be undefined' + ); + }); + + /** + * ### .NaN + * Asserts that the target is `NaN`. + * + * expect('foo').to.be.NaN; + * expect(4).not.to.be.NaN; + * + * @name NaN + * @api public + */ + + Assertion.addProperty('NaN', function () { + this.assert( + isNaN(flag(this, 'object')) + , 'expected #{this} to be NaN' + , 'expected #{this} not to be NaN' + ); + }); + + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi' + * , bar = null + * , baz; + * + * expect(foo).to.exist; + * expect(bar).to.not.exist; + * expect(baz).to.not.exist; + * + * @name exist + * @api public + */ + + Assertion.addProperty('exist', function () { + this.assert( + null != flag(this, 'object') + , 'expected #{this} to exist' + , 'expected #{this} to not exist' + ); + }); + + + /** + * ### .empty + * + * Asserts that the target's length is `0`. For arrays and strings, it checks + * the `length` property. For objects, it gets the count of + * enumerable keys. + * + * expect([]).to.be.empty; + * expect('').to.be.empty; + * expect({}).to.be.empty; + * + * @name empty + * @api public + */ + + Assertion.addProperty('empty', function () { + var obj = flag(this, 'object') + , expected = obj; + + if (Array.isArray(obj) || 'string' === typeof object) { + expected = obj.length; + } else if (typeof obj === 'object') { + expected = Object.keys(obj).length; + } + + this.assert( + !expected + , 'expected #{this} to be empty' + , 'expected #{this} not to be empty' + ); + }); + + /** + * ### .arguments + * + * Asserts that the target is an arguments object. + * + * function test () { + * expect(arguments).to.be.arguments; + * } + * + * @name arguments + * @alias Arguments + * @api public + */ + + function checkArguments () { + var obj = flag(this, 'object') + , type = Object.prototype.toString.call(obj); + this.assert( + '[object Arguments]' === type + , 'expected #{this} to be arguments but got ' + type + , 'expected #{this} to not be arguments' + ); + } + + Assertion.addProperty('arguments', checkArguments); + Assertion.addProperty('Arguments', checkArguments); + + /** + * ### .equal(value) + * + * Asserts that the target is strictly equal (`===`) to `value`. + * Alternately, if the `deep` flag is set, asserts that + * the target is deeply equal to `value`. + * + * expect('hello').to.equal('hello'); + * expect(42).to.equal(42); + * expect(1).to.not.equal(true); + * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); + * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); + * + * @name equal + * @alias equals + * @alias eq + * @alias deep.equal + * @param {Mixed} value + * @param {String} message _optional_ + * @api public + */ + + function assertEqual (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'deep')) { + return this.eql(val); + } else { + this.assert( + val === obj + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{exp}' + , val + , this._obj + , true + ); + } + } + + Assertion.addMethod('equal', assertEqual); + Assertion.addMethod('equals', assertEqual); + Assertion.addMethod('eq', assertEqual); + + /** + * ### .eql(value) + * + * Asserts that the target is deeply equal to `value`. + * + * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); + * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); + * + * @name eql + * @alias eqls + * @param {Mixed} value + * @param {String} message _optional_ + * @api public + */ + + function assertEql(obj, msg) { + if (msg) flag(this, 'message', msg); + this.assert( + _.eql(obj, flag(this, 'object')) + , 'expected #{this} to deeply equal #{exp}' + , 'expected #{this} to not deeply equal #{exp}' + , obj + , this._obj + , true + ); + } + + Assertion.addMethod('eql', assertEql); + Assertion.addMethod('eqls', assertEql); + + /** + * ### .above(value) + * + * Asserts that the target is greater than `value`. + * + * expect(10).to.be.above(5); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * + * @name above + * @alias gt + * @alias greaterThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertAbove (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len > n + , 'expected #{this} to have a length above #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj > n + , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most ' + n + ); + } + } + + Assertion.addMethod('above', assertAbove); + Assertion.addMethod('gt', assertAbove); + Assertion.addMethod('greaterThan', assertAbove); + + /** + * ### .least(value) + * + * Asserts that the target is greater than or equal to `value`. + * + * expect(10).to.be.at.least(10); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.least(2); + * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * + * @name least + * @alias gte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertLeast (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= n + , 'expected #{this} to have a length at least #{exp} but got #{act}' + , 'expected #{this} to have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj >= n + , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below ' + n + ); + } + } + + Assertion.addMethod('least', assertLeast); + Assertion.addMethod('gte', assertLeast); + + /** + * ### .below(value) + * + * Asserts that the target is less than `value`. + * + * expect(5).to.be.below(10); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * + * @name below + * @alias lt + * @alias lessThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertBelow (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len < n + , 'expected #{this} to have a length below #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj < n + , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least ' + n + ); + } + } + + Assertion.addMethod('below', assertBelow); + Assertion.addMethod('lt', assertBelow); + Assertion.addMethod('lessThan', assertBelow); + + /** + * ### .most(value) + * + * Asserts that the target is less than or equal to `value`. + * + * expect(5).to.be.at.most(5); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.most(4); + * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * + * @name most + * @alias lte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertMost (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len <= n + , 'expected #{this} to have a length at most #{exp} but got #{act}' + , 'expected #{this} to have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj <= n + , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above ' + n + ); + } + } + + Assertion.addMethod('most', assertMost); + Assertion.addMethod('lte', assertMost); + + /** + * ### .within(start, finish) + * + * Asserts that the target is within a range. + * + * expect(7).to.be.within(5,10); + * + * Can also be used in conjunction with `length` to + * assert a length range. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name within + * @param {Number} start lowerbound inclusive + * @param {Number} finish upperbound inclusive + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('within', function (start, finish, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , range = start + '..' + finish; + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= start && len <= finish + , 'expected #{this} to have a length within ' + range + , 'expected #{this} to not have a length within ' + range + ); + } else { + this.assert( + obj >= start && obj <= finish + , 'expected #{this} to be within ' + range + , 'expected #{this} to not be within ' + range + ); + } + }); + + /** + * ### .instanceof(constructor) + * + * Asserts that the target is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , Chai = new Tea('chai'); + * + * expect(Chai).to.be.an.instanceof(Tea); + * expect([ 1, 2, 3 ]).to.be.instanceof(Array); + * + * @name instanceof + * @param {Constructor} constructor + * @param {String} message _optional_ + * @alias instanceOf + * @api public + */ + + function assertInstanceOf (constructor, msg) { + if (msg) flag(this, 'message', msg); + var name = _.getName(constructor); + this.assert( + flag(this, 'object') instanceof constructor + , 'expected #{this} to be an instance of ' + name + , 'expected #{this} to not be an instance of ' + name + ); + }; + + Assertion.addMethod('instanceof', assertInstanceOf); + Assertion.addMethod('instanceOf', assertInstanceOf); + + /** + * ### .property(name, [value]) + * + * Asserts that the target has a property `name`, optionally asserting that + * the value of that property is strictly equal to `value`. + * If the `deep` flag is set, you can use dot- and bracket-notation for deep + * references into objects and arrays. + * + * // simple referencing + * var obj = { foo: 'bar' }; + * expect(obj).to.have.property('foo'); + * expect(obj).to.have.property('foo', 'bar'); + * + * // deep referencing + * var deepObj = { + * green: { tea: 'matcha' } + * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] + * }; + * + * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); + * + * You can also use an array as the starting point of a `deep.property` + * assertion, or traverse nested arrays. + * + * var arr = [ + * [ 'chai', 'matcha', 'konacha' ] + * , [ { tea: 'chai' } + * , { tea: 'matcha' } + * , { tea: 'konacha' } ] + * ]; + * + * expect(arr).to.have.deep.property('[0][1]', 'matcha'); + * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); + * + * Furthermore, `property` changes the subject of the assertion + * to be the value of that property from the original object. This + * permits for further chainable assertions on that property. + * + * expect(obj).to.have.property('foo') + * .that.is.a('string'); + * expect(deepObj).to.have.property('green') + * .that.is.an('object') + * .that.deep.equals({ tea: 'matcha' }); + * expect(deepObj).to.have.property('teas') + * .that.is.an('array') + * .with.deep.property('[2]') + * .that.deep.equals({ tea: 'konacha' }); + * + * Note that dots and bracket in `name` must be backslash-escaped when + * the `deep` flag is set, while they must NOT be escaped when the `deep` + * flag is not set. + * + * // simple referencing + * var css = { '.link[target]': 42 }; + * expect(css).to.have.property('.link[target]', 42); + * + * // deep referencing + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name property + * @alias deep.property + * @param {String} name + * @param {Mixed} value (optional) + * @param {String} message _optional_ + * @returns value of property for chaining + * @api public + */ + + Assertion.addMethod('property', function (name, val, msg) { + if (msg) flag(this, 'message', msg); + + var isDeep = !!flag(this, 'deep') + , descriptor = isDeep ? 'deep property ' : 'property ' + , negate = flag(this, 'negate') + , obj = flag(this, 'object') + , pathInfo = isDeep ? _.getPathInfo(name, obj) : null + , hasProperty = isDeep + ? pathInfo.exists + : _.hasProperty(name, obj) + , value = isDeep + ? pathInfo.value + : obj[name]; + + if (negate && arguments.length > 1) { + if (undefined === value) { + msg = (msg != null) ? msg + ': ' : ''; + throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + } + } else { + this.assert( + hasProperty + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to not have ' + descriptor + _.inspect(name)); + } + + if (arguments.length > 1) { + this.assert( + val === value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + , val + , value + ); + } + + flag(this, 'object', value); + }); + + + /** + * ### .ownProperty(name) + * + * Asserts that the target has an own property `name`. + * + * expect('test').to.have.ownProperty('length'); + * + * @name ownProperty + * @alias haveOwnProperty + * @param {String} name + * @param {String} message _optional_ + * @api public + */ + + function assertOwnProperty (name, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + obj.hasOwnProperty(name) + , 'expected #{this} to have own property ' + _.inspect(name) + , 'expected #{this} to not have own property ' + _.inspect(name) + ); + } + + Assertion.addMethod('ownProperty', assertOwnProperty); + Assertion.addMethod('haveOwnProperty', assertOwnProperty); + + /** + * ### .ownPropertyDescriptor(name[, descriptor[, message]]) + * + * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. + * + * expect('test').to.have.ownPropertyDescriptor('length'); + * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); + * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); + * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); + * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); + * + * @name ownPropertyDescriptor + * @alias haveOwnPropertyDescriptor + * @param {String} name + * @param {Object} descriptor _optional_ + * @param {String} message _optional_ + * @api public + */ + + function assertOwnPropertyDescriptor (name, descriptor, msg) { + if (typeof descriptor === 'string') { + msg = descriptor; + descriptor = null; + } + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); + if (actualDescriptor && descriptor) { + this.assert( + _.eql(descriptor, actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) + , descriptor + , actualDescriptor + , true + ); + } else { + this.assert( + actualDescriptor + , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) + , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) + ); + } + flag(this, 'object', actualDescriptor); + } + + Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); + Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); + + /** + * ### .length + * + * Sets the `doLength` flag later used as a chain precursor to a value + * comparison for the `length` property. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * *Deprecation notice:* Using `length` as an assertion will be deprecated + * in version 2.4.0 and removed in 3.0.0. Code using the old style of + * asserting for `length` property value using `length(value)` should be + * switched to use `lengthOf(value)` instead. + * + * @name length + * @api public + */ + + /** + * ### .lengthOf(value[, message]) + * + * Asserts that the target's `length` property has + * the expected value. + * + * expect([ 1, 2, 3]).to.have.lengthOf(3); + * expect('foobar').to.have.lengthOf(6); + * + * @name lengthOf + * @param {Number} length + * @param {String} message _optional_ + * @api public + */ + + function assertLengthChain () { + flag(this, 'doLength', true); + } + + function assertLength (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + + this.assert( + len == n + , 'expected #{this} to have a length of #{exp} but got #{act}' + , 'expected #{this} to not have a length of #{act}' + , n + , len + ); + } + + Assertion.addChainableMethod('length', assertLength, assertLengthChain); + Assertion.addMethod('lengthOf', assertLength); + + /** + * ### .match(regexp) + * + * Asserts that the target matches a regular expression. + * + * expect('foobar').to.match(/^foo/); + * + * @name match + * @alias matches + * @param {RegExp} RegularExpression + * @param {String} message _optional_ + * @api public + */ + function assertMatch(re, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + re.exec(obj) + , 'expected #{this} to match ' + re + , 'expected #{this} not to match ' + re + ); + } + + Assertion.addMethod('match', assertMatch); + Assertion.addMethod('matches', assertMatch); + + /** + * ### .string(string) + * + * Asserts that the string target contains another string. + * + * expect('foobar').to.have.string('bar'); + * + * @name string + * @param {String} string + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('string', function (str, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('string'); + + this.assert( + ~obj.indexOf(str) + , 'expected #{this} to contain ' + _.inspect(str) + , 'expected #{this} to not contain ' + _.inspect(str) + ); + }); + + + /** + * ### .keys(key1, [key2], [...]) + * + * Asserts that the target contains any or all of the passed-in keys. + * Use in combination with `any`, `all`, `contains`, or `have` will affect + * what will pass. + * + * When used in conjunction with `any`, at least one key that is passed + * in must exist in the target object. This is regardless whether or not + * the `have` or `contain` qualifiers are used. Note, either `any` or `all` + * should be used in the assertion. If neither are used, the assertion is + * defaulted to `all`. + * + * When both `all` and `contain` are used, the target object must have at + * least all of the passed-in keys but may have more keys not listed. + * + * When both `all` and `have` are used, the target object must both contain + * all of the passed-in keys AND the number of keys in the target object must + * match the number of keys passed in (in other words, a target object must + * have all and only all of the passed-in keys). + * + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); + * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); + * + * + * @name keys + * @alias key + * @param {...String|Array|Object} keys + * @api public + */ + + function assertKeys (keys) { + var obj = flag(this, 'object') + , str + , ok = true + , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; + + switch (_.type(keys)) { + case "array": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + break; + case "object": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + keys = Object.keys(keys); + break; + default: + keys = Array.prototype.slice.call(arguments); + } + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(obj) + , expected = keys + , len = keys.length + , any = flag(this, 'any') + , all = flag(this, 'all'); + + if (!any && !all) { + all = true; + } + + // Has any + if (any) { + var intersection = expected.filter(function(key) { + return ~actual.indexOf(key); + }); + ok = intersection.length > 0; + } + + // Has all + if (all) { + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + if (!flag(this, 'negate') && !flag(this, 'contains')) { + ok = ok && keys.length == actual.length; + } + } + + // Key string + if (len > 1) { + keys = keys.map(function(key){ + return _.inspect(key); + }); + var last = keys.pop(); + if (all) { + str = keys.join(', ') + ', and ' + last; + } + if (any) { + str = keys.join(', ') + ', or ' + last; + } + } else { + str = _.inspect(keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected #{this} to ' + str + , 'expected #{this} to not ' + str + , expected.slice(0).sort() + , actual.sort() + , true + ); + } + + Assertion.addMethod('keys', assertKeys); + Assertion.addMethod('key', assertKeys); + + /** + * ### .throw(constructor) + * + * Asserts that the function target will throw a specific error, or specific type of error + * (as determined using `instanceof`), optionally with a RegExp or string inclusion test + * for the error's message. + * + * var err = new ReferenceError('This is a bad function.'); + * var fn = function () { throw err; } + * expect(fn).to.throw(ReferenceError); + * expect(fn).to.throw(Error); + * expect(fn).to.throw(/bad function/); + * expect(fn).to.not.throw('good function'); + * expect(fn).to.throw(ReferenceError, /bad function/); + * expect(fn).to.throw(err); + * + * Please note that when a throw expectation is negated, it will check each + * parameter independently, starting with error constructor type. The appropriate way + * to check for the existence of a type of error but for a message that does not match + * is to use `and`. + * + * expect(fn).to.throw(ReferenceError) + * .and.not.throw(/good function/); + * + * @name throw + * @alias throws + * @alias Throw + * @param {ErrorConstructor} constructor + * @param {String|RegExp} expected error message + * @param {String} message _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @returns error for chaining (null if no error) + * @api public + */ + + function assertThrows (constructor, errMsg, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('function'); + + var thrown = false + , desiredError = null + , name = null + , thrownError = null; + + if (arguments.length === 0) { + errMsg = null; + constructor = null; + } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { + errMsg = constructor; + constructor = null; + } else if (constructor && constructor instanceof Error) { + desiredError = constructor; + constructor = null; + errMsg = null; + } else if (typeof constructor === 'function') { + name = constructor.prototype.name; + if (!name || (name === 'Error' && constructor !== Error)) { + name = constructor.name || (new constructor()).name; + } + } else { + constructor = null; + } + + try { + obj(); + } catch (err) { + // first, check desired error + if (desiredError) { + this.assert( + err === desiredError + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (err instanceof Error ? err.toString() : err) + ); + + flag(this, 'object', err); + return this; + } + + // next, check constructor + if (constructor) { + this.assert( + err instanceof constructor + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp} but #{act} was thrown' + , name + , (err instanceof Error ? err.toString() : err) + ); + + if (!errMsg) { + flag(this, 'object', err); + return this; + } + } + + // next, check message + var message = 'error' === _.type(err) && "message" in err + ? err.message + : '' + err; + + if ((message != null) && errMsg && errMsg instanceof RegExp) { + this.assert( + errMsg.exec(message) + , 'expected #{this} to throw error matching #{exp} but got #{act}' + , 'expected #{this} to throw error not matching #{exp}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else if ((message != null) && errMsg && 'string' === typeof errMsg) { + this.assert( + ~message.indexOf(errMsg) + , 'expected #{this} to throw error including #{exp} but got #{act}' + , 'expected #{this} to throw error not including #{act}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else { + thrown = true; + thrownError = err; + } + } + + var actuallyGot = '' + , expectedThrown = name !== null + ? name + : desiredError + ? '#{exp}' //_.inspect(desiredError) + : 'an error'; + + if (thrown) { + actuallyGot = ' but #{act} was thrown' + } + + this.assert( + thrown === true + , 'expected #{this} to throw ' + expectedThrown + actuallyGot + , 'expected #{this} to not throw ' + expectedThrown + actuallyGot + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (thrownError instanceof Error ? thrownError.toString() : thrownError) + ); + + flag(this, 'object', thrownError); + }; + + Assertion.addMethod('throw', assertThrows); + Assertion.addMethod('throws', assertThrows); + Assertion.addMethod('Throw', assertThrows); + + /** + * ### .respondTo(method) + * + * Asserts that the object or class target will respond to a method. + * + * Klass.prototype.bar = function(){}; + * expect(Klass).to.respondTo('bar'); + * expect(obj).to.respondTo('bar'); + * + * To check if a constructor will respond to a static function, + * set the `itself` flag. + * + * Klass.baz = function(){}; + * expect(Klass).itself.to.respondTo('baz'); + * + * @name respondTo + * @alias respondsTo + * @param {String} method + * @param {String} message _optional_ + * @api public + */ + + function respondTo (method, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , itself = flag(this, 'itself') + , context = ('function' === _.type(obj) && !itself) + ? obj.prototype[method] + : obj[method]; + + this.assert( + 'function' === typeof context + , 'expected #{this} to respond to ' + _.inspect(method) + , 'expected #{this} to not respond to ' + _.inspect(method) + ); + } + + Assertion.addMethod('respondTo', respondTo); + Assertion.addMethod('respondsTo', respondTo); + + /** + * ### .itself + * + * Sets the `itself` flag, later used by the `respondTo` assertion. + * + * function Foo() {} + * Foo.bar = function() {} + * Foo.prototype.baz = function() {} + * + * expect(Foo).itself.to.respondTo('bar'); + * expect(Foo).itself.not.to.respondTo('baz'); + * + * @name itself + * @api public + */ + + Assertion.addProperty('itself', function () { + flag(this, 'itself', true); + }); + + /** + * ### .satisfy(method) + * + * Asserts that the target passes a given truth test. + * + * expect(1).to.satisfy(function(num) { return num > 0; }); + * + * @name satisfy + * @alias satisfies + * @param {Function} matcher + * @param {String} message _optional_ + * @api public + */ + + function satisfy (matcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var result = matcher(obj); + this.assert( + result + , 'expected #{this} to satisfy ' + _.objDisplay(matcher) + , 'expected #{this} to not satisfy' + _.objDisplay(matcher) + , this.negate ? false : true + , result + ); + } + + Assertion.addMethod('satisfy', satisfy); + Assertion.addMethod('satisfies', satisfy); + + /** + * ### .closeTo(expected, delta) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * expect(1.5).to.be.closeTo(1, 0.5); + * + * @name closeTo + * @alias approximately + * @param {Number} expected + * @param {Number} delta + * @param {String} message _optional_ + * @api public + */ + + function closeTo(expected, delta, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj, msg).is.a('number'); + if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { + throw new Error('the arguments to closeTo or approximately must be numbers'); + } + + this.assert( + Math.abs(obj - expected) <= delta + , 'expected #{this} to be close to ' + expected + ' +/- ' + delta + , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta + ); + } + + Assertion.addMethod('closeTo', closeTo); + Assertion.addMethod('approximately', closeTo); + + function isSubsetOf(subset, superset, cmp) { + return subset.every(function(elem) { + if (!cmp) return superset.indexOf(elem) !== -1; + + return superset.some(function(elem2) { + return cmp(elem, elem2); + }); + }) + } + + /** + * ### .members(set) + * + * Asserts that the target is a superset of `set`, + * or that the target and `set` have the same strictly-equal (===) members. + * Alternately, if the `deep` flag is set, set members are compared for deep + * equality. + * + * expect([1, 2, 3]).to.include.members([3, 2]); + * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); + * + * expect([4, 2]).to.have.members([2, 4]); + * expect([5, 2]).to.not.have.members([5, 2, 1]); + * + * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); + * + * @name members + * @param {Array} set + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('members', function (subset, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj).to.be.an('array'); + new Assertion(subset).to.be.an('array'); + + var cmp = flag(this, 'deep') ? _.eql : undefined; + + if (flag(this, 'contains')) { + return this.assert( + isSubsetOf(subset, obj, cmp) + , 'expected #{this} to be a superset of #{act}' + , 'expected #{this} to not be a superset of #{act}' + , obj + , subset + ); + } + + this.assert( + isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) + , 'expected #{this} to have the same members as #{act}' + , 'expected #{this} to not have the same members as #{act}' + , obj + , subset + ); + }); + + /** + * ### .oneOf(list) + * + * Assert that a value appears somewhere in the top level of array `list`. + * + * expect('a').to.be.oneOf(['a', 'b', 'c']); + * expect(9).to.not.be.oneOf(['z']); + * expect([3]).to.not.be.oneOf([1, 2, [3]]); + * + * var three = [3]; + * // for object-types, contents are not compared + * expect(three).to.not.be.oneOf([1, 2, [3]]); + * // comparing references works + * expect(three).to.be.oneOf([1, 2, three]); + * + * @name oneOf + * @param {Array<*>} list + * @param {String} message _optional_ + * @api public + */ + + function oneOf (list, msg) { + if (msg) flag(this, 'message', msg); + var expected = flag(this, 'object'); + new Assertion(list).to.be.an('array'); + + this.assert( + list.indexOf(expected) > -1 + , 'expected #{this} to be one of #{exp}' + , 'expected #{this} to not be one of #{exp}' + , list + , expected + ); + } + + Assertion.addMethod('oneOf', oneOf); + + + /** + * ### .change(function) + * + * Asserts that a function changes an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 3 }; + * var noChangeFn = function() { return 'foo' + 'bar'; } + * expect(fn).to.change(obj, 'val'); + * expect(noChangFn).to.not.change(obj, 'val') + * + * @name change + * @alias changes + * @alias Change + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + function assertChanges (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + initial !== object[prop] + , 'expected .' + prop + ' to change' + , 'expected .' + prop + ' to not change' + ); + } + + Assertion.addChainableMethod('change', assertChanges); + Assertion.addChainableMethod('changes', assertChanges); + + /** + * ### .increase(function) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * expect(fn).to.increase(obj, 'val'); + * + * @name increase + * @alias increases + * @alias Increase + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + function assertIncreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial > 0 + , 'expected .' + prop + ' to increase' + , 'expected .' + prop + ' to not increase' + ); + } + + Assertion.addChainableMethod('increase', assertIncreases); + Assertion.addChainableMethod('increases', assertIncreases); + + /** + * ### .decrease(function) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * expect(fn).to.decrease(obj, 'val'); + * + * @name decrease + * @alias decreases + * @alias Decrease + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + function assertDecreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial < 0 + , 'expected .' + prop + ' to decrease' + , 'expected .' + prop + ' to not decrease' + ); + } + + Assertion.addChainableMethod('decrease', assertDecreases); + Assertion.addChainableMethod('decreases', assertDecreases); + + /** + * ### .extensible + * + * Asserts that the target is extensible (can have new properties added to + * it). + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect({}).to.be.extensible; + * expect(nonExtensibleObject).to.not.be.extensible; + * expect(sealedObject).to.not.be.extensible; + * expect(frozenObject).to.not.be.extensible; + * + * @name extensible + * @api public + */ + + Assertion.addProperty('extensible', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isExtensible; + + try { + isExtensible = Object.isExtensible(obj); + } catch (err) { + if (err instanceof TypeError) isExtensible = false; + else throw err; + } + + this.assert( + isExtensible + , 'expected #{this} to be extensible' + , 'expected #{this} to not be extensible' + ); + }); + + /** + * ### .sealed + * + * Asserts that the target is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect(sealedObject).to.be.sealed; + * expect(frozenObject).to.be.sealed; + * expect({}).to.not.be.sealed; + * + * @name sealed + * @api public + */ + + Assertion.addProperty('sealed', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isSealed; + + try { + isSealed = Object.isSealed(obj); + } catch (err) { + if (err instanceof TypeError) isSealed = true; + else throw err; + } + + this.assert( + isSealed + , 'expected #{this} to be sealed' + , 'expected #{this} to not be sealed' + ); + }); + + /** + * ### .frozen + * + * Asserts that the target is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * + * expect(frozenObject).to.be.frozen; + * expect({}).to.not.be.frozen; + * + * @name frozen + * @api public + */ + + Assertion.addProperty('frozen', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isFrozen; + + try { + isFrozen = Object.isFrozen(obj); + } catch (err) { + if (err instanceof TypeError) isFrozen = true; + else throw err; + } + + this.assert( + isFrozen + , 'expected #{this} to be frozen' + , 'expected #{this} to not be frozen' + ); + }); +}; + +},{}],6:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + + +module.exports = function (chai, util) { + + /*! + * Chai dependencies. + */ + + var Assertion = chai.Assertion + , flag = util.flag; + + /*! + * Module export. + */ + + /** + * ### assert(expression, message) + * + * Write your own test expressions. + * + * assert('foo' !== 'bar', 'foo is not bar'); + * assert(Array.isArray([]), 'empty arrays are arrays'); + * + * @param {Mixed} expression to test for truthiness + * @param {String} message to display on error + * @name assert + * @api public + */ + + var assert = chai.assert = function (express, errmsg) { + var test = new Assertion(null, null, chai.assert); + test.assert( + express + , errmsg + , '[ negation message unavailable ]' + ); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. Node.js `assert` module-compatible. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @api public + */ + + assert.fail = function (actual, expected, message, operator) { + message = message || 'assert.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, assert.fail); + }; + + /** + * ### .isOk(object, [message]) + * + * Asserts that `object` is truthy. + * + * assert.isOk('everything', 'everything is ok'); + * assert.isOk(false, 'this will fail'); + * + * @name isOk + * @alias ok + * @param {Mixed} object to test + * @param {String} message + * @api public + */ + + assert.isOk = function (val, msg) { + new Assertion(val, msg).is.ok; + }; + + /** + * ### .isNotOk(object, [message]) + * + * Asserts that `object` is falsy. + * + * assert.isNotOk('everything', 'this will fail'); + * assert.isNotOk(false, 'this will pass'); + * + * @name isNotOk + * @alias notOk + * @param {Mixed} object to test + * @param {String} message + * @api public + */ + + assert.isNotOk = function (val, msg) { + new Assertion(val, msg).is.not.ok; + }; + + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * assert.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.equal = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.equal); + + test.assert( + exp == flag(test, 'object') + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{act}' + , exp + , act + ); + }; + + /** + * ### .notEqual(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * assert.notEqual(3, 4, 'these numbers are not equal'); + * + * @name notEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notEqual = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.notEqual); + + test.assert( + exp != flag(test, 'object') + , 'expected #{this} to not equal #{exp}' + , 'expected #{this} to equal #{act}' + , exp + , act + ); + }; + + /** + * ### .strictEqual(actual, expected, [message]) + * + * Asserts strict equality (`===`) of `actual` and `expected`. + * + * assert.strictEqual(true, true, 'these booleans are strictly equal'); + * + * @name strictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.strictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.equal(exp); + }; + + /** + * ### .notStrictEqual(actual, expected, [message]) + * + * Asserts strict inequality (`!==`) of `actual` and `expected`. + * + * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); + * + * @name notStrictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notStrictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.equal(exp); + }; + + /** + * ### .deepEqual(actual, expected, [message]) + * + * Asserts that `actual` is deeply equal to `expected`. + * + * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); + * + * @name deepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.deepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.eql(exp); + }; + + /** + * ### .notDeepEqual(actual, expected, [message]) + * + * Assert that `actual` is not deeply equal to `expected`. + * + * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); + * + * @name notDeepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notDeepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.eql(exp); + }; + + /** + * ### .isAbove(valueToCheck, valueToBeAbove, [message]) + * + * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` + * + * assert.isAbove(5, 2, '5 is strictly greater than 2'); + * + * @name isAbove + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAbove + * @param {String} message + * @api public + */ + + assert.isAbove = function (val, abv, msg) { + new Assertion(val, msg).to.be.above(abv); + }; + + /** + * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) + * + * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast` + * + * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); + * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); + * + * @name isAtLeast + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtLeast + * @param {String} message + * @api public + */ + + assert.isAtLeast = function (val, atlst, msg) { + new Assertion(val, msg).to.be.least(atlst); + }; + + /** + * ### .isBelow(valueToCheck, valueToBeBelow, [message]) + * + * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` + * + * assert.isBelow(3, 6, '3 is strictly less than 6'); + * + * @name isBelow + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeBelow + * @param {String} message + * @api public + */ + + assert.isBelow = function (val, blw, msg) { + new Assertion(val, msg).to.be.below(blw); + }; + + /** + * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) + * + * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost` + * + * assert.isAtMost(3, 6, '3 is less than or equal to 6'); + * assert.isAtMost(4, 4, '4 is less than or equal to 4'); + * + * @name isAtMost + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtMost + * @param {String} message + * @api public + */ + + assert.isAtMost = function (val, atmst, msg) { + new Assertion(val, msg).to.be.most(atmst); + }; + + /** + * ### .isTrue(value, [message]) + * + * Asserts that `value` is true. + * + * var teaServed = true; + * assert.isTrue(teaServed, 'the tea has been served'); + * + * @name isTrue + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isTrue = function (val, msg) { + new Assertion(val, msg).is['true']; + }; + + /** + * ### .isNotTrue(value, [message]) + * + * Asserts that `value` is not true. + * + * var tea = 'tasty chai'; + * assert.isNotTrue(tea, 'great, time for tea!'); + * + * @name isNotTrue + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotTrue = function (val, msg) { + new Assertion(val, msg).to.not.equal(true); + }; + + /** + * ### .isFalse(value, [message]) + * + * Asserts that `value` is false. + * + * var teaServed = false; + * assert.isFalse(teaServed, 'no tea yet? hmm...'); + * + * @name isFalse + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFalse = function (val, msg) { + new Assertion(val, msg).is['false']; + }; + + /** + * ### .isNotFalse(value, [message]) + * + * Asserts that `value` is not false. + * + * var tea = 'tasty chai'; + * assert.isNotFalse(tea, 'great, time for tea!'); + * + * @name isNotFalse + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotFalse = function (val, msg) { + new Assertion(val, msg).to.not.equal(false); + }; + + /** + * ### .isNull(value, [message]) + * + * Asserts that `value` is null. + * + * assert.isNull(err, 'there was no error'); + * + * @name isNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNull = function (val, msg) { + new Assertion(val, msg).to.equal(null); + }; + + /** + * ### .isNotNull(value, [message]) + * + * Asserts that `value` is not null. + * + * var tea = 'tasty chai'; + * assert.isNotNull(tea, 'great, time for tea!'); + * + * @name isNotNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNull = function (val, msg) { + new Assertion(val, msg).to.not.equal(null); + }; + + /** + * ### .isNaN + * Asserts that value is NaN + * + * assert.isNaN('foo', 'foo is NaN'); + * + * @name isNaN + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNaN = function (val, msg) { + new Assertion(val, msg).to.be.NaN; + }; + + /** + * ### .isNotNaN + * Asserts that value is not NaN + * + * assert.isNotNaN(4, '4 is not NaN'); + * + * @name isNotNaN + * @param {Mixed} value + * @param {String} message + * @api public + */ + assert.isNotNaN = function (val, msg) { + new Assertion(val, msg).not.to.be.NaN; + }; + + /** + * ### .isUndefined(value, [message]) + * + * Asserts that `value` is `undefined`. + * + * var tea; + * assert.isUndefined(tea, 'no tea defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isUndefined = function (val, msg) { + new Assertion(val, msg).to.equal(undefined); + }; + + /** + * ### .isDefined(value, [message]) + * + * Asserts that `value` is not `undefined`. + * + * var tea = 'cup of chai'; + * assert.isDefined(tea, 'tea has been defined'); + * + * @name isDefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isDefined = function (val, msg) { + new Assertion(val, msg).to.not.equal(undefined); + }; + + /** + * ### .isFunction(value, [message]) + * + * Asserts that `value` is a function. + * + * function serveTea() { return 'cup of tea'; }; + * assert.isFunction(serveTea, 'great, we can have tea now'); + * + * @name isFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFunction = function (val, msg) { + new Assertion(val, msg).to.be.a('function'); + }; + + /** + * ### .isNotFunction(value, [message]) + * + * Asserts that `value` is _not_ a function. + * + * var serveTea = [ 'heat', 'pour', 'sip' ]; + * assert.isNotFunction(serveTea, 'great, we have listed the steps'); + * + * @name isNotFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotFunction = function (val, msg) { + new Assertion(val, msg).to.not.be.a('function'); + }; + + /** + * ### .isObject(value, [message]) + * + * Asserts that `value` is an object (as revealed by + * `Object.prototype.toString`). + * + * var selection = { name: 'Chai', serve: 'with spices' }; + * assert.isObject(selection, 'tea selection is an object'); + * + * @name isObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isObject = function (val, msg) { + new Assertion(val, msg).to.be.a('object'); + }; + + /** + * ### .isNotObject(value, [message]) + * + * Asserts that `value` is _not_ an object. + * + * var selection = 'chai' + * assert.isNotObject(selection, 'tea selection is not an object'); + * assert.isNotObject(null, 'null is not an object'); + * + * @name isNotObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotObject = function (val, msg) { + new Assertion(val, msg).to.not.be.a('object'); + }; + + /** + * ### .isArray(value, [message]) + * + * Asserts that `value` is an array. + * + * var menu = [ 'green', 'chai', 'oolong' ]; + * assert.isArray(menu, 'what kind of tea do we want?'); + * + * @name isArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isArray = function (val, msg) { + new Assertion(val, msg).to.be.an('array'); + }; + + /** + * ### .isNotArray(value, [message]) + * + * Asserts that `value` is _not_ an array. + * + * var menu = 'green|chai|oolong'; + * assert.isNotArray(menu, 'what kind of tea do we want?'); + * + * @name isNotArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotArray = function (val, msg) { + new Assertion(val, msg).to.not.be.an('array'); + }; + + /** + * ### .isString(value, [message]) + * + * Asserts that `value` is a string. + * + * var teaOrder = 'chai'; + * assert.isString(teaOrder, 'order placed'); + * + * @name isString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isString = function (val, msg) { + new Assertion(val, msg).to.be.a('string'); + }; + + /** + * ### .isNotString(value, [message]) + * + * Asserts that `value` is _not_ a string. + * + * var teaOrder = 4; + * assert.isNotString(teaOrder, 'order placed'); + * + * @name isNotString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotString = function (val, msg) { + new Assertion(val, msg).to.not.be.a('string'); + }; + + /** + * ### .isNumber(value, [message]) + * + * Asserts that `value` is a number. + * + * var cups = 2; + * assert.isNumber(cups, 'how many cups'); + * + * @name isNumber + * @param {Number} value + * @param {String} message + * @api public + */ + + assert.isNumber = function (val, msg) { + new Assertion(val, msg).to.be.a('number'); + }; + + /** + * ### .isNotNumber(value, [message]) + * + * Asserts that `value` is _not_ a number. + * + * var cups = '2 cups please'; + * assert.isNotNumber(cups, 'how many cups'); + * + * @name isNotNumber + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNumber = function (val, msg) { + new Assertion(val, msg).to.not.be.a('number'); + }; + + /** + * ### .isBoolean(value, [message]) + * + * Asserts that `value` is a boolean. + * + * var teaReady = true + * , teaServed = false; + * + * assert.isBoolean(teaReady, 'is the tea ready'); + * assert.isBoolean(teaServed, 'has tea been served'); + * + * @name isBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isBoolean = function (val, msg) { + new Assertion(val, msg).to.be.a('boolean'); + }; + + /** + * ### .isNotBoolean(value, [message]) + * + * Asserts that `value` is _not_ a boolean. + * + * var teaReady = 'yep' + * , teaServed = 'nope'; + * + * assert.isNotBoolean(teaReady, 'is the tea ready'); + * assert.isNotBoolean(teaServed, 'has tea been served'); + * + * @name isNotBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotBoolean = function (val, msg) { + new Assertion(val, msg).to.not.be.a('boolean'); + }; + + /** + * ### .typeOf(value, name, [message]) + * + * Asserts that `value`'s type is `name`, as determined by + * `Object.prototype.toString`. + * + * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); + * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); + * assert.typeOf('tea', 'string', 'we have a string'); + * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); + * assert.typeOf(null, 'null', 'we have a null'); + * assert.typeOf(undefined, 'undefined', 'we have an undefined'); + * + * @name typeOf + * @param {Mixed} value + * @param {String} name + * @param {String} message + * @api public + */ + + assert.typeOf = function (val, type, msg) { + new Assertion(val, msg).to.be.a(type); + }; + + /** + * ### .notTypeOf(value, name, [message]) + * + * Asserts that `value`'s type is _not_ `name`, as determined by + * `Object.prototype.toString`. + * + * assert.notTypeOf('tea', 'number', 'strings are not numbers'); + * + * @name notTypeOf + * @param {Mixed} value + * @param {String} typeof name + * @param {String} message + * @api public + */ + + assert.notTypeOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.a(type); + }; + + /** + * ### .instanceOf(object, constructor, [message]) + * + * Asserts that `value` is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new Tea('chai'); + * + * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); + * + * @name instanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.instanceOf = function (val, type, msg) { + new Assertion(val, msg).to.be.instanceOf(type); + }; + + /** + * ### .notInstanceOf(object, constructor, [message]) + * + * Asserts `value` is not an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new String('chai'); + * + * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); + * + * @name notInstanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.notInstanceOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.instanceOf(type); + }; + + /** + * ### .include(haystack, needle, [message]) + * + * Asserts that `haystack` includes `needle`. Works + * for strings and arrays. + * + * assert.include('foobar', 'bar', 'foobar contains string "bar"'); + * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * + * @name include + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @api public + */ + + assert.include = function (exp, inc, msg) { + new Assertion(exp, msg, assert.include).include(inc); + }; + + /** + * ### .notInclude(haystack, needle, [message]) + * + * Asserts that `haystack` does not include `needle`. Works + * for strings and arrays. + * + * assert.notInclude('foobar', 'baz', 'string not include substring'); + * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); + * + * @name notInclude + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @api public + */ + + assert.notInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notInclude).not.include(inc); + }; + + /** + * ### .match(value, regexp, [message]) + * + * Asserts that `value` matches the regular expression `regexp`. + * + * assert.match('foobar', /^foo/, 'regexp matches'); + * + * @name match + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.match = function (exp, re, msg) { + new Assertion(exp, msg).to.match(re); + }; + + /** + * ### .notMatch(value, regexp, [message]) + * + * Asserts that `value` does not match the regular expression `regexp`. + * + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * + * @name notMatch + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg).to.not.match(re); + }; + + /** + * ### .property(object, property, [message]) + * + * Asserts that `object` has a property named by `property`. + * + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * + * @name property + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.property(prop); + }; + + /** + * ### .notProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`. + * + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * + * @name notProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.property(prop); + }; + + /** + * ### .deepProperty(object, property, [message]) + * + * Asserts that `object` has a property named by `property`, which can be a + * string using dot- and bracket-notation for deep reference. + * + * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * + * @name deepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.deepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.deep.property(prop); + }; + + /** + * ### .notDeepProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for deep reference. + * + * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * + * @name notDeepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notDeepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop); + }; + + /** + * ### .propertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. + * + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.property(prop, val); + }; + + /** + * ### .propertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. + * + * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * + * @name propertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.property(prop, val); + }; + + /** + * ### .deepPropertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for deep + * reference. + * + * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.deep.property(prop, val); + }; + + /** + * ### .deepPropertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. `property` can use dot- and + * bracket-notation for deep reference. + * + * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * + * @name deepPropertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop, val); + }; + + /** + * ### .lengthOf(object, length, [message]) + * + * Asserts that `object` has a `length` property with the expected value. + * + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 6, 'string has length of 6'); + * + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message + * @api public + */ + + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg).to.have.length(len); + }; + + /** + * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * assert.throws(fn, 'function throws a reference error'); + * assert.throws(fn, /function throws a reference error/); + * assert.throws(fn, ReferenceError); + * assert.throws(fn, ReferenceError, 'function throws a reference error'); + * assert.throws(fn, ReferenceError, /function throws a reference error/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.throws = function (fn, errt, errs, msg) { + if ('string' === typeof errt || errt instanceof RegExp) { + errs = errt; + errt = null; + } + + var assertErr = new Assertion(fn, msg).to.throw(errt, errs); + return flag(assertErr, 'object'); + }; + + /** + * ### .doesNotThrow(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * assert.doesNotThrow(fn, Error, 'function does not throw'); + * + * @name doesNotThrow + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.doesNotThrow = function (fn, type, msg) { + if ('string' === typeof type) { + msg = type; + type = null; + } + + new Assertion(fn, msg).to.not.Throw(type); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + var ok; + switch(operator) { + case '==': + ok = val == val2; + break; + case '===': + ok = val === val2; + break; + case '>': + ok = val > val2; + break; + case '>=': + ok = val >= val2; + break; + case '<': + ok = val < val2; + break; + case '<=': + ok = val <= val2; + break; + case '!=': + ok = val != val2; + break; + case '!==': + ok = val !== val2; + break; + default: + throw new Error('Invalid operator "' + operator + '"'); + } + var test = new Assertion(ok, msg); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.closeTo(exp, delta); + }; + + /** + * ### .approximately(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.approximately(1.5, 1, 0.5, 'numbers are close'); + * + * @name approximately + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @api public + */ + + assert.approximately = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.approximately(exp, delta); + }; + + /** + * ### .sameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members. + * Order is not taken into account. + * + * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * + * @name sameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @api public + */ + + assert.sameMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.members(set2); + } + + /** + * ### .sameDeepMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members - using a deep equality checking. + * Order is not taken into account. + * + * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); + * + * @name sameDeepMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @api public + */ + + assert.sameDeepMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.deep.members(set2); + } + + /** + * ### .includeMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset`. + * Order is not taken into account. + * + * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); + * + * @name includeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @api public + */ + + assert.includeMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.members(subset); + } + + /** + * ### .oneOf(inList, list, [message]) + * + * Asserts that non-object, non-array value `inList` appears in the flat array `list`. + * + * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); + * + * @name oneOf + * @param {*} inList + * @param {Array<*>} list + * @param {String} message + * @api public + */ + + assert.oneOf = function (inList, list, msg) { + new Assertion(inList, msg).to.be.oneOf(list); + } + + /** + * ### .changes(function, object, property) + * + * Asserts that a function changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 22 }; + * assert.changes(fn, obj, 'val'); + * + * @name changes + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.changes = function (fn, obj, prop) { + new Assertion(fn).to.change(obj, prop); + } + + /** + * ### .doesNotChange(function, object, property) + * + * Asserts that a function does not changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { console.log('foo'); }; + * assert.doesNotChange(fn, obj, 'val'); + * + * @name doesNotChange + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.doesNotChange = function (fn, obj, prop) { + new Assertion(fn).to.not.change(obj, prop); + } + + /** + * ### .increases(function, object, property) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 13 }; + * assert.increases(fn, obj, 'val'); + * + * @name increases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.increases = function (fn, obj, prop) { + new Assertion(fn).to.increase(obj, prop); + } + + /** + * ### .doesNotIncrease(function, object, property) + * + * Asserts that a function does not increase object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 8 }; + * assert.doesNotIncrease(fn, obj, 'val'); + * + * @name doesNotIncrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.doesNotIncrease = function (fn, obj, prop) { + new Assertion(fn).to.not.increase(obj, prop); + } + + /** + * ### .decreases(function, object, property) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.decreases(fn, obj, 'val'); + * + * @name decreases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.decreases = function (fn, obj, prop) { + new Assertion(fn).to.decrease(obj, prop); + } + + /** + * ### .doesNotDecrease(function, object, property) + * + * Asserts that a function does not decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * assert.doesNotDecrease(fn, obj, 'val'); + * + * @name doesNotDecrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @api public + */ + + assert.doesNotDecrease = function (fn, obj, prop) { + new Assertion(fn).to.not.decrease(obj, prop); + } + + /*! + * ### .ifError(object) + * + * Asserts if value is not a false value, and throws if it is a true value. + * This is added to allow for chai to be a drop-in replacement for Node's + * assert class. + * + * var err = new Error('I am a custom error'); + * assert.ifError(err); // Rethrows err! + * + * @name ifError + * @param {Object} object + * @api public + */ + + assert.ifError = function (val) { + if (val) { + throw(val); + } + }; + + /** + * ### .isExtensible(object) + * + * Asserts that `object` is extensible (can have new properties added to it). + * + * assert.isExtensible({}); + * + * @name isExtensible + * @alias extensible + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isExtensible = function (obj, msg) { + new Assertion(obj, msg).to.be.extensible; + }; + + /** + * ### .isNotExtensible(object) + * + * Asserts that `object` is _not_ extensible. + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freese({}); + * + * assert.isNotExtensible(nonExtensibleObject); + * assert.isNotExtensible(sealedObject); + * assert.isNotExtensible(frozenObject); + * + * @name isNotExtensible + * @alias notExtensible + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isNotExtensible = function (obj, msg) { + new Assertion(obj, msg).to.not.be.extensible; + }; + + /** + * ### .isSealed(object) + * + * Asserts that `object` is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.seal({}); + * + * assert.isSealed(sealedObject); + * assert.isSealed(frozenObject); + * + * @name isSealed + * @alias sealed + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isSealed = function (obj, msg) { + new Assertion(obj, msg).to.be.sealed; + }; + + /** + * ### .isNotSealed(object) + * + * Asserts that `object` is _not_ sealed. + * + * assert.isNotSealed({}); + * + * @name isNotSealed + * @alias notSealed + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isNotSealed = function (obj, msg) { + new Assertion(obj, msg).to.not.be.sealed; + }; + + /** + * ### .isFrozen(object) + * + * Asserts that `object` is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * assert.frozen(frozenObject); + * + * @name isFrozen + * @alias frozen + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isFrozen = function (obj, msg) { + new Assertion(obj, msg).to.be.frozen; + }; + + /** + * ### .isNotFrozen(object) + * + * Asserts that `object` is _not_ frozen. + * + * assert.isNotFrozen({}); + * + * @name isNotFrozen + * @alias notFrozen + * @param {Object} object + * @param {String} message _optional_ + * @api public + */ + + assert.isNotFrozen = function (obj, msg) { + new Assertion(obj, msg).to.not.be.frozen; + }; + + /*! + * Aliases. + */ + + (function alias(name, as){ + assert[as] = assert[name]; + return alias; + }) + ('isOk', 'ok') + ('isNotOk', 'notOk') + ('throws', 'throw') + ('throws', 'Throw') + ('isExtensible', 'extensible') + ('isNotExtensible', 'notExtensible') + ('isSealed', 'sealed') + ('isNotSealed', 'notSealed') + ('isFrozen', 'frozen') + ('isNotFrozen', 'notFrozen'); +}; + +},{}],7:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @api public + */ + + chai.expect.fail = function (actual, expected, message, operator) { + message = message || 'expect.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, chai.expect.fail); + }; +}; + +},{}],8:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +module.exports = function (chai, util) { + var Assertion = chai.Assertion; + + function loadShould () { + // explicitly define this method as function as to have it's name to include as `ssfi` + function shouldGetter() { + if (this instanceof String || this instanceof Number || this instanceof Boolean ) { + return new Assertion(this.valueOf(), null, shouldGetter); + } + return new Assertion(this, null, shouldGetter); + } + function shouldSetter(value) { + // See https://github.com/chaijs/chai/issues/86: this makes + // `whatever.should = someValue` actually set `someValue`, which is + // especially useful for `global.should = require('chai').should()`. + // + // Note that we have to use [[DefineProperty]] instead of [[Put]] + // since otherwise we would trigger this very setter! + Object.defineProperty(this, 'should', { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } + // modify Object.prototype to have `should` + Object.defineProperty(Object.prototype, 'should', { + set: shouldSetter + , get: shouldGetter + , configurable: true + }); + + var should = {}; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @api public + */ + + should.fail = function (actual, expected, message, operator) { + message = message || 'should.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, should.fail); + }; + + should.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.equal(val2); + }; + + should.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + should.exist = function (val, msg) { + new Assertion(val, msg).to.exist; + } + + // negation + should.not = {} + + should.not.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.not.equal(val2); + }; + + should.not.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.not.Throw(errt, errs); + }; + + should.not.exist = function (val, msg) { + new Assertion(val, msg).to.not.exist; + } + + should['throw'] = should['Throw']; + should.not['throw'] = should.not['Throw']; + + return should; + }; + + chai.should = loadShould; + chai.Should = loadShould; +}; + +},{}],9:[function(require,module,exports){ +/*! + * Chai - addChainingMethod utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var transferFlags = require('./transferFlags'); +var flag = require('./flag'); +var config = require('../config'); + +/*! + * Module variables + */ + +// Check whether `__proto__` is supported +var hasProtoSupport = '__proto__' in Object; + +// Without `__proto__` support, this module will need to add properties to a function. +// However, some Function.prototype methods cannot be overwritten, +// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). +var excludeNames = /^(?:length|name|arguments|caller)$/; + +// Cache `Function` properties +var call = Function.prototype.call, + apply = Function.prototype.apply; + +/** + * ### addChainableMethod (ctx, name, method, chainingBehavior) + * + * Adds a method to an object, such that the method can also be chained. + * + * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); + * + * The result can then be used as both a method assertion, executing both `method` and + * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. + * + * expect(fooStr).to.be.foo('bar'); + * expect(fooStr).to.be.foo.equal('foo'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for `name`, when called + * @param {Function} chainingBehavior function to be called every time the property is accessed + * @name addChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + if (typeof chainingBehavior !== 'function') { + chainingBehavior = function () { }; + } + + var chainableBehavior = { + method: method + , chainingBehavior: chainingBehavior + }; + + // save the methods so we can overwrite them later, if we need to. + if (!ctx.__methods) { + ctx.__methods = {}; + } + ctx.__methods[name] = chainableBehavior; + + Object.defineProperty(ctx, name, + { get: function () { + chainableBehavior.chainingBehavior.call(this); + + var assert = function assert() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', assert); + var result = chainableBehavior.method.apply(this, arguments); + return result === undefined ? this : result; + }; + + // Use `__proto__` if available + if (hasProtoSupport) { + // Inherit all properties from the object by replacing the `Function` prototype + var prototype = assert.__proto__ = Object.create(this); + // Restore the `call` and `apply` methods from `Function` + prototype.call = call; + prototype.apply = apply; + } + // Otherwise, redefine all properties (slow!) + else { + var asserterNames = Object.getOwnPropertyNames(ctx); + asserterNames.forEach(function (asserterName) { + if (!excludeNames.test(asserterName)) { + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); + Object.defineProperty(assert, asserterName, pd); + } + }); + } + + transferFlags(this, assert); + return assert; + } + , configurable: true + }); +}; + +},{"../config":4,"./flag":13,"./transferFlags":29}],10:[function(require,module,exports){ +/*! + * Chai - addMethod utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var config = require('../config'); + +/** + * ### .addMethod (ctx, name, method) + * + * Adds a method to the prototype of an object. + * + * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(fooStr).to.be.foo('bar'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for name + * @name addMethod + * @api public + */ +var flag = require('./flag'); + +module.exports = function (ctx, name, method) { + ctx[name] = function () { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', ctx[name]); + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{"../config":4,"./flag":13}],11:[function(require,module,exports){ +/*! + * Chai - addProperty utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var config = require('../config'); +var flag = require('./flag'); + +/** + * ### addProperty (ctx, name, getter) + * + * Adds a property to the prototype of an object. + * + * utils.addProperty(chai.Assertion.prototype, 'foo', function () { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.instanceof(Foo); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.foo; + * + * @param {Object} ctx object to which the property is added + * @param {String} name of property to add + * @param {Function} getter function to be used for name + * @name addProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + Object.defineProperty(ctx, name, + { get: function addProperty() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', addProperty); + + var result = getter.call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{"../config":4,"./flag":13}],12:[function(require,module,exports){ +/*! + * Chai - expectTypes utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### expectTypes(obj, types) + * + * Ensures that the object being tested against is of a valid type. + * + * utils.expectTypes(this, ['array', 'object', 'string']); + * + * @param {Mixed} obj constructed Assertion + * @param {Array} type A list of allowed types for this assertion + * @name expectTypes + * @api public + */ + +var AssertionError = require('assertion-error'); +var flag = require('./flag'); +var type = require('type-detect'); + +module.exports = function (obj, types) { + var obj = flag(obj, 'object'); + types = types.map(function (t) { return t.toLowerCase(); }); + types.sort(); + + // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum' + var str = types.map(function (t, index) { + var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; + var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; + return or + art + ' ' + t; + }).join(', '); + + if (!types.some(function (expected) { return type(obj) === expected; })) { + throw new AssertionError( + 'object tested must be ' + str + ', but ' + type(obj) + ' given' + ); + } +}; + +},{"./flag":13,"assertion-error":30,"type-detect":35}],13:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### flag(object, key, [value]) + * + * Get or set a flag value on an object. If a + * value is provided it will be set, else it will + * return the currently set value or `undefined` if + * the value is not set. + * + * utils.flag(this, 'foo', 'bar'); // setter + * utils.flag(this, 'foo'); // getter, returns `bar` + * + * @param {Object} object constructed Assertion + * @param {String} key + * @param {Mixed} value (optional) + * @name flag + * @api private + */ + +module.exports = function (obj, key, value) { + var flags = obj.__flags || (obj.__flags = Object.create(null)); + if (arguments.length === 3) { + flags[key] = value; + } else { + return flags[key]; + } +}; + +},{}],14:[function(require,module,exports){ +/*! + * Chai - getActual utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * # getActual(object, [actual]) + * + * Returns the `actual` value for an Assertion + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + +module.exports = function (obj, args) { + return args.length > 4 ? args[4] : obj._obj; +}; + +},{}],15:[function(require,module,exports){ +/*! + * Chai - getEnumerableProperties utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### .getEnumerableProperties(object) + * + * This allows the retrieval of enumerable property names of an object, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @name getEnumerableProperties + * @api public + */ + +module.exports = function getEnumerableProperties(object) { + var result = []; + for (var name in object) { + result.push(name); + } + return result; +}; + +},{}],16:[function(require,module,exports){ +/*! + * Chai - message composition utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag') + , getActual = require('./getActual') + , inspect = require('./inspect') + , objDisplay = require('./objDisplay'); + +/** + * ### .getMessage(object, message, negateMessage) + * + * Construct the error message based on flags + * and template tags. Template tags will return + * a stringified inspection of the object referenced. + * + * Message template tags: + * - `#{this}` current asserted object + * - `#{act}` actual value + * - `#{exp}` expected value + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @name getMessage + * @api public + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , val = flag(obj, 'object') + , expected = args[3] + , actual = getActual(obj, args) + , msg = negate ? args[2] : args[1] + , flagMsg = flag(obj, 'message'); + + if(typeof msg === "function") msg = msg(); + msg = msg || ''; + msg = msg + .replace(/#{this}/g, objDisplay(val)) + .replace(/#{act}/g, objDisplay(actual)) + .replace(/#{exp}/g, objDisplay(expected)); + + return flagMsg ? flagMsg + ': ' + msg : msg; +}; + +},{"./flag":13,"./getActual":14,"./inspect":23,"./objDisplay":24}],17:[function(require,module,exports){ +/*! + * Chai - getName utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * # getName(func) + * + * Gets the name of a function, in a cross-browser way. + * + * @param {Function} a function (usually a constructor) + */ + +module.exports = function (func) { + if (func.name) return func.name; + + var match = /^\s?function ([^(]*)\(/.exec(func); + return match && match[1] ? match[1] : ""; +}; + +},{}],18:[function(require,module,exports){ +/*! + * Chai - getPathInfo utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var hasProperty = require('./hasProperty'); + +/** + * ### .getPathInfo(path, object) + * + * This allows the retrieval of property info in an + * object given a string path. + * + * The path info consists of an object with the + * following properties: + * + * * parent - The parent object of the property referenced by `path` + * * name - The name of the final property, a number if it was an array indexer + * * value - The value of the property, if it exists, otherwise `undefined` + * * exists - Whether the property exists or not + * + * @param {String} path + * @param {Object} object + * @returns {Object} info + * @name getPathInfo + * @api public + */ + +module.exports = function getPathInfo(path, obj) { + var parsed = parsePath(path), + last = parsed[parsed.length - 1]; + + var info = { + parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, + name: last.p || last.i, + value: _getPathValue(parsed, obj) + }; + info.exists = hasProperty(info.name, info.parent); + + return info; +}; + + +/*! + * ## parsePath(path) + * + * Helper function used to parse string object + * paths. Use in conjunction with `_getPathValue`. + * + * var parsed = parsePath('myobject.property.subprop'); + * + * ### Paths: + * + * * Can be as near infinitely deep and nested + * * Arrays are also valid using the formal `myobject.document[3].property`. + * * Literal dots and brackets (not delimiter) must be backslash-escaped. + * + * @param {String} path + * @returns {Object} parsed + * @api private + */ + +function parsePath (path) { + var str = path.replace(/([^\\])\[/g, '$1.[') + , parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function (value) { + var re = /^\[(\d+)\]$/ + , mArr = re.exec(value); + if (mArr) return { i: parseFloat(mArr[1]) }; + else return { p: value.replace(/\\([.\[\]])/g, '$1') }; + }); +} + + +/*! + * ## _getPathValue(parsed, obj) + * + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. + * + * var value = getPathValue(parsed, obj); + * + * @param {Object} parsed definition from `parsePath`. + * @param {Object} object to search against + * @param {Number} object to search against + * @returns {Object|Undefined} value + * @api private + */ + +function _getPathValue (parsed, obj, index) { + var tmp = obj + , res; + + index = (index === undefined ? parsed.length : index); + + for (var i = 0, l = index; i < l; i++) { + var part = parsed[i]; + if (tmp) { + if ('undefined' !== typeof part.p) + tmp = tmp[part.p]; + else if ('undefined' !== typeof part.i) + tmp = tmp[part.i]; + if (i == (l - 1)) res = tmp; + } else { + res = undefined; + } + } + return res; +} + +},{"./hasProperty":21}],19:[function(require,module,exports){ +/*! + * Chai - getPathValue utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ + +var getPathInfo = require('./getPathInfo'); + +/** + * ### .getPathValue(path, object) + * + * This allows the retrieval of values in an + * object given a string path. + * + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * } + * + * The following would be the results. + * + * getPathValue('prop1.str', obj); // Hello + * getPathValue('prop1.att[2]', obj); // b + * getPathValue('prop2.arr[0].nested', obj); // Universe + * + * @param {String} path + * @param {Object} object + * @returns {Object} value or `undefined` + * @name getPathValue + * @api public + */ +module.exports = function(path, obj) { + var info = getPathInfo(path, obj); + return info.value; +}; + +},{"./getPathInfo":18}],20:[function(require,module,exports){ +/*! + * Chai - getProperties utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### .getProperties(object) + * + * This allows the retrieval of property names of an object, enumerable or not, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @name getProperties + * @api public + */ + +module.exports = function getProperties(object) { + var result = Object.getOwnPropertyNames(object); + + function addProperty(property) { + if (result.indexOf(property) === -1) { + result.push(property); + } + } + + var proto = Object.getPrototypeOf(object); + while (proto !== null) { + Object.getOwnPropertyNames(proto).forEach(addProperty); + proto = Object.getPrototypeOf(proto); + } + + return result; +}; + +},{}],21:[function(require,module,exports){ +/*! + * Chai - hasProperty utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +var type = require('type-detect'); + +/** + * ### .hasProperty(object, name) + * + * This allows checking whether an object has + * named property or numeric array index. + * + * Basically does the same thing as the `in` + * operator but works properly with natives + * and null/undefined values. + * + * var obj = { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * + * The following would be the results. + * + * hasProperty('str', obj); // true + * hasProperty('constructor', obj); // true + * hasProperty('bar', obj); // false + * + * hasProperty('length', obj.str); // true + * hasProperty(1, obj.str); // true + * hasProperty(5, obj.str); // false + * + * hasProperty('length', obj.arr); // true + * hasProperty(2, obj.arr); // true + * hasProperty(3, obj.arr); // false + * + * @param {Objuect} object + * @param {String|Number} name + * @returns {Boolean} whether it exists + * @name getPathInfo + * @api public + */ + +var literals = { + 'number': Number + , 'string': String +}; + +module.exports = function hasProperty(name, obj) { + var ot = type(obj); + + // Bad Object, obviously no props at all + if(ot === 'null' || ot === 'undefined') + return false; + + // The `in` operator does not work with certain literals + // box these before the check + if(literals[ot] && typeof obj !== 'object') + obj = new literals[ot](obj); + + return name in obj; +}; + +},{"type-detect":35}],22:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Main exports + */ + +var exports = module.exports = {}; + +/*! + * test utility + */ + +exports.test = require('./test'); + +/*! + * type utility + */ + +exports.type = require('type-detect'); + +/*! + * expectTypes utility + */ +exports.expectTypes = require('./expectTypes'); + +/*! + * message utility + */ + +exports.getMessage = require('./getMessage'); + +/*! + * actual utility + */ + +exports.getActual = require('./getActual'); + +/*! + * Inspect util + */ + +exports.inspect = require('./inspect'); + +/*! + * Object Display util + */ + +exports.objDisplay = require('./objDisplay'); + +/*! + * Flag utility + */ + +exports.flag = require('./flag'); + +/*! + * Flag transferring utility + */ + +exports.transferFlags = require('./transferFlags'); + +/*! + * Deep equal utility + */ + +exports.eql = require('deep-eql'); + +/*! + * Deep path value + */ + +exports.getPathValue = require('./getPathValue'); + +/*! + * Deep path info + */ + +exports.getPathInfo = require('./getPathInfo'); + +/*! + * Check if a property exists + */ + +exports.hasProperty = require('./hasProperty'); + +/*! + * Function name + */ + +exports.getName = require('./getName'); + +/*! + * add Property + */ + +exports.addProperty = require('./addProperty'); + +/*! + * add Method + */ + +exports.addMethod = require('./addMethod'); + +/*! + * overwrite Property + */ + +exports.overwriteProperty = require('./overwriteProperty'); + +/*! + * overwrite Method + */ + +exports.overwriteMethod = require('./overwriteMethod'); + +/*! + * Add a chainable method + */ + +exports.addChainableMethod = require('./addChainableMethod'); + +/*! + * Overwrite chainable method + */ + +exports.overwriteChainableMethod = require('./overwriteChainableMethod'); + +},{"./addChainableMethod":9,"./addMethod":10,"./addProperty":11,"./expectTypes":12,"./flag":13,"./getActual":14,"./getMessage":16,"./getName":17,"./getPathInfo":18,"./getPathValue":19,"./hasProperty":21,"./inspect":23,"./objDisplay":24,"./overwriteChainableMethod":25,"./overwriteMethod":26,"./overwriteProperty":27,"./test":28,"./transferFlags":29,"deep-eql":31,"type-detect":35}],23:[function(require,module,exports){ +// This is (almost) directly from Node.js utils +// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js + +var getName = require('./getName'); +var getProperties = require('./getProperties'); +var getEnumerableProperties = require('./getEnumerableProperties'); + +module.exports = inspect; + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + */ +function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: function (str) { return str; } + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); +} + +// Returns true if object is a DOM element. +var isDOMElement = function (object) { + if (typeof HTMLElement === 'object') { + return object instanceof HTMLElement; + } else { + return object && + typeof object === 'object' && + object.nodeType === 1 && + typeof object.nodeName === 'string'; + } +}; + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes); + if (typeof ret !== 'string') { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // If this is a DOM element, try to get the outer HTML. + if (isDOMElement(value)) { + if ('outerHTML' in value) { + return value.outerHTML; + // This value does not have an outerHTML attribute, + // it could still be an XML element + } else { + // Attempt to serialize it + try { + if (document.xmlVersion) { + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(value); + } else { + // Firefox 11- do not support outerHTML + // It does, however, support innerHTML + // Use the following to render the element + var ns = "http://www.w3.org/1999/xhtml"; + var container = document.createElementNS(ns, '_'); + + container.appendChild(value.cloneNode(false)); + html = container.innerHTML + .replace('><', '>' + value.innerHTML + '<'); + container.innerHTML = ''; + return html; + } + } catch (err) { + // This could be a non-native DOM implementation, + // continue with the normal flow: + // printing the element as if it is an object. + } + } + } + + // Look up the keys of the object. + var visibleKeys = getEnumerableProperties(value); + var keys = ctx.showHidden ? getProperties(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + // In IE, errors have a single `stack` property, or if they are vanilla `Error`, + // a `stack` plus `description` property; ignore those for consistency. + if (keys.length === 0 || (isError(value) && ( + (keys.length === 1 && keys[0] === 'stack') || + (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') + ))) { + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + return ctx.stylize('[Function' + nameSuffix + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + base = ' [Function' + nameSuffix + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + return formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + if (value === 0 && (1/value) === -Infinity) { + return ctx.stylize('-0', 'number'); + } + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Setter]', 'special'); + } + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(value[key]) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, value[key], null); + } else { + str = formatValue(ctx, value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + +function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); +} + +function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; +} + +function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; +} + +function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; +} + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + +},{"./getEnumerableProperties":15,"./getName":17,"./getProperties":20}],24:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var inspect = require('./inspect'); +var config = require('../config'); + +/** + * ### .objDisplay (object) + * + * Determines if an object or an array matches + * criteria to be inspected in-line for error + * messages or should be truncated. + * + * @param {Mixed} javascript object to inspect + * @name objDisplay + * @api public + */ + +module.exports = function (obj) { + var str = inspect(obj) + , type = Object.prototype.toString.call(obj); + + if (config.truncateThreshold && str.length >= config.truncateThreshold) { + if (type === '[object Function]') { + return !obj.name || obj.name === '' + ? '[Function]' + : '[Function: ' + obj.name + ']'; + } else if (type === '[object Array]') { + return '[ Array(' + obj.length + ') ]'; + } else if (type === '[object Object]') { + var keys = Object.keys(obj) + , kstr = keys.length > 2 + ? keys.splice(0, 2).join(', ') + ', ...' + : keys.join(', '); + return '{ Object (' + kstr + ') }'; + } else { + return str; + } + } else { + return str; + } +}; + +},{"../config":4,"./inspect":23}],25:[function(require,module,exports){ +/*! + * Chai - overwriteChainableMethod utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) + * + * Overwites an already existing chainable method + * and provides access to the previous function or + * property. Must return functions to be used for + * name. + * + * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', + * function (_super) { + * } + * , function (_super) { + * } + * ); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteChainableMethod('foo', fn, fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.have.length(3); + * expect(myFoo).to.have.length.above(3); + * + * @param {Object} ctx object whose method / property is to be overwritten + * @param {String} name of method / property to overwrite + * @param {Function} method function that returns a function to be used for name + * @param {Function} chainingBehavior function that returns a function to be used for property + * @name overwriteChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + var chainableBehavior = ctx.__methods[name]; + + var _chainingBehavior = chainableBehavior.chainingBehavior; + chainableBehavior.chainingBehavior = function () { + var result = chainingBehavior(_chainingBehavior).call(this); + return result === undefined ? this : result; + }; + + var _method = chainableBehavior.method; + chainableBehavior.method = function () { + var result = method(_method).apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{}],26:[function(require,module,exports){ +/*! + * Chai - overwriteMethod utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### overwriteMethod (ctx, name, fn) + * + * Overwites an already existing method and provides + * access to previous function. Must return function + * to be used for name. + * + * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { + * return function (str) { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.value).to.equal(str); + * } else { + * _super.apply(this, arguments); + * } + * } + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.equal('bar'); + * + * @param {Object} ctx object whose method is to be overwritten + * @param {String} name of method to overwrite + * @param {Function} method function that returns a function to be used for name + * @name overwriteMethod + * @api public + */ + +module.exports = function (ctx, name, method) { + var _method = ctx[name] + , _super = function () { return this; }; + + if (_method && 'function' === typeof _method) + _super = _method; + + ctx[name] = function () { + var result = method(_super).apply(this, arguments); + return result === undefined ? this : result; + } +}; + +},{}],27:[function(require,module,exports){ +/*! + * Chai - overwriteProperty utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### overwriteProperty (ctx, name, fn) + * + * Overwites an already existing property getter and provides + * access to previous value. Must return function to use as getter. + * + * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { + * return function () { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.name).to.equal('bar'); + * } else { + * _super.call(this); + * } + * } + * }); + * + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.ok; + * + * @param {Object} ctx object whose property is to be overwritten + * @param {String} name of property to overwrite + * @param {Function} getter function that returns a getter function to be used for name + * @name overwriteProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + var _get = Object.getOwnPropertyDescriptor(ctx, name) + , _super = function () {}; + + if (_get && 'function' === typeof _get.get) + _super = _get.get + + Object.defineProperty(ctx, name, + { get: function () { + var result = getter(_super).call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{}],28:[function(require,module,exports){ +/*! + * Chai - test utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag'); + +/** + * # test(object, expression) + * + * Test and object for expression. + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , expr = args[0]; + return negate ? !expr : expr; +}; + +},{"./flag":13}],29:[function(require,module,exports){ +/*! + * Chai - transferFlags utility + * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/** + * ### transferFlags(assertion, object, includeAll = true) + * + * Transfer all the flags for `assertion` to `object`. If + * `includeAll` is set to `false`, then the base Chai + * assertion flags (namely `object`, `ssfi`, and `message`) + * will not be transferred. + * + * + * var newAssertion = new Assertion(); + * utils.transferFlags(assertion, newAssertion); + * + * var anotherAsseriton = new Assertion(myObj); + * utils.transferFlags(assertion, anotherAssertion, false); + * + * @param {Assertion} assertion the assertion to transfer the flags from + * @param {Object} object the object to transfer the flags to; usually a new assertion + * @param {Boolean} includeAll + * @name transferFlags + * @api private + */ + +module.exports = function (assertion, object, includeAll) { + var flags = assertion.__flags || (assertion.__flags = Object.create(null)); + + if (!object.__flags) { + object.__flags = Object.create(null); + } + + includeAll = arguments.length === 3 ? includeAll : true; + + for (var flag in flags) { + if (includeAll || + (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + object.__flags[flag] = flags[flag]; + } + } +}; + +},{}],30:[function(require,module,exports){ +/*! + * assertion-error + * Copyright(c) 2013 Jake Luer <jake@qualiancy.com> + * MIT Licensed + */ + +/*! + * Return a function that will copy properties from + * one object to another excluding any originally + * listed. Returned function will create a new `{}`. + * + * @param {String} excluded properties ... + * @return {Function} + */ + +function exclude () { + var excludes = [].slice.call(arguments); + + function excludeProps (res, obj) { + Object.keys(obj).forEach(function (key) { + if (!~excludes.indexOf(key)) res[key] = obj[key]; + }); + } + + return function extendExclude () { + var args = [].slice.call(arguments) + , i = 0 + , res = {}; + + for (; i < args.length; i++) { + excludeProps(res, args[i]); + } + + return res; + }; +}; + +/*! + * Primary Exports + */ + +module.exports = AssertionError; + +/** + * ### AssertionError + * + * An extension of the JavaScript `Error` constructor for + * assertion and validation scenarios. + * + * @param {String} message + * @param {Object} properties to include (optional) + * @param {callee} start stack function (optional) + */ + +function AssertionError (message, _props, ssf) { + var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') + , props = extend(_props || {}); + + // default values + this.message = message || 'Unspecified AssertionError'; + this.showDiff = false; + + // copy from properties + for (var key in props) { + this[key] = props[key]; + } + + // capture stack trace + ssf = ssf || arguments.callee; + if (ssf && Error.captureStackTrace) { + Error.captureStackTrace(this, ssf); + } else { + this.stack = new Error().stack; + } +} + +/*! + * Inherit from Error.prototype + */ + +AssertionError.prototype = Object.create(Error.prototype); + +/*! + * Statically set name + */ + +AssertionError.prototype.name = 'AssertionError'; + +/*! + * Ensure correct constructor + */ + +AssertionError.prototype.constructor = AssertionError; + +/** + * Allow errors to be converted to JSON for static transfer. + * + * @param {Boolean} include stack (default: `true`) + * @return {Object} object that can be `JSON.stringify` + */ + +AssertionError.prototype.toJSON = function (stack) { + var extend = exclude('constructor', 'toJSON', 'stack') + , props = extend({ name: this.name }, this); + + // include stack if exists and not turned off + if (false !== stack && this.stack) { + props.stack = this.stack; + } + + return props; +}; + +},{}],31:[function(require,module,exports){ +module.exports = require('./lib/eql'); + +},{"./lib/eql":32}],32:[function(require,module,exports){ +/*! + * deep-eql + * Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var type = require('type-detect'); + +/*! + * Buffer.isBuffer browser shim + */ + +var Buffer; +try { Buffer = require('buffer').Buffer; } +catch(ex) { + Buffer = {}; + Buffer.isBuffer = function() { return false; } +} + +/*! + * Primary Export + */ + +module.exports = deepEqual; + +/** + * Assert super-strict (egal) equality between + * two objects of any type. + * + * @param {Mixed} a + * @param {Mixed} b + * @param {Array} memoised (optional) + * @return {Boolean} equal match + */ + +function deepEqual(a, b, m) { + if (sameValue(a, b)) { + return true; + } else if ('date' === type(a)) { + return dateEqual(a, b); + } else if ('regexp' === type(a)) { + return regexpEqual(a, b); + } else if (Buffer.isBuffer(a)) { + return bufferEqual(a, b); + } else if ('arguments' === type(a)) { + return argumentsEqual(a, b, m); + } else if (!typeEqual(a, b)) { + return false; + } else if (('object' !== type(a) && 'object' !== type(b)) + && ('array' !== type(a) && 'array' !== type(b))) { + return sameValue(a, b); + } else { + return objectEqual(a, b, m); + } +} + +/*! + * Strict (egal) equality test. Ensures that NaN always + * equals NaN and `-0` does not equal `+0`. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} equal match + */ + +function sameValue(a, b) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + return a !== a && b !== b; +} + +/*! + * Compare the types of two given objects and + * return if they are equal. Note that an Array + * has a type of `array` (not `object`) and arguments + * have a type of `arguments` (not `array`/`object`). + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function typeEqual(a, b) { + return type(a) === type(b); +} + +/*! + * Compare two Date objects by asserting that + * the time values are equal using `saveValue`. + * + * @param {Date} a + * @param {Date} b + * @return {Boolean} result + */ + +function dateEqual(a, b) { + if ('date' !== type(b)) return false; + return sameValue(a.getTime(), b.getTime()); +} + +/*! + * Compare two regular expressions by converting them + * to string and checking for `sameValue`. + * + * @param {RegExp} a + * @param {RegExp} b + * @return {Boolean} result + */ + +function regexpEqual(a, b) { + if ('regexp' !== type(b)) return false; + return sameValue(a.toString(), b.toString()); +} + +/*! + * Assert deep equality of two `arguments` objects. + * Unfortunately, these must be sliced to arrays + * prior to test to ensure no bad behavior. + * + * @param {Arguments} a + * @param {Arguments} b + * @param {Array} memoize (optional) + * @return {Boolean} result + */ + +function argumentsEqual(a, b, m) { + if ('arguments' !== type(b)) return false; + a = [].slice.call(a); + b = [].slice.call(b); + return deepEqual(a, b, m); +} + +/*! + * Get enumerable properties of a given object. + * + * @param {Object} a + * @return {Array} property names + */ + +function enumerable(a) { + var res = []; + for (var key in a) res.push(key); + return res; +} + +/*! + * Simple equality for flat iterable objects + * such as Arrays or Node.js buffers. + * + * @param {Iterable} a + * @param {Iterable} b + * @return {Boolean} result + */ + +function iterableEqual(a, b) { + if (a.length !== b.length) return false; + + var i = 0; + var match = true; + + for (; i < a.length; i++) { + if (a[i] !== b[i]) { + match = false; + break; + } + } + + return match; +} + +/*! + * Extension to `iterableEqual` specifically + * for Node.js Buffers. + * + * @param {Buffer} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function bufferEqual(a, b) { + if (!Buffer.isBuffer(b)) return false; + return iterableEqual(a, b); +} + +/*! + * Block for `objectEqual` ensuring non-existing + * values don't get in. + * + * @param {Mixed} object + * @return {Boolean} result + */ + +function isValue(a) { + return a !== null && a !== undefined; +} + +/*! + * Recursively check the equality of two objects. + * Once basic sameness has been established it will + * defer to `deepEqual` for each enumerable key + * in the object. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function objectEqual(a, b, m) { + if (!isValue(a) || !isValue(b)) { + return false; + } + + if (a.prototype !== b.prototype) { + return false; + } + + var i; + if (m) { + for (i = 0; i < m.length; i++) { + if ((m[i][0] === a && m[i][1] === b) + || (m[i][0] === b && m[i][1] === a)) { + return true; + } + } + } else { + m = []; + } + + try { + var ka = enumerable(a); + var kb = enumerable(b); + } catch (ex) { + return false; + } + + ka.sort(); + kb.sort(); + + if (!iterableEqual(ka, kb)) { + return false; + } + + m.push([ a, b ]); + + var key; + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], m)) { + return false; + } + } + + return true; +} + +},{"buffer":undefined,"type-detect":33}],33:[function(require,module,exports){ +module.exports = require('./lib/type'); + +},{"./lib/type":34}],34:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Array]': 'array' + , '[object RegExp]': 'regexp' + , '[object Function]': 'function' + , '[object Arguments]': 'arguments' + , '[object Date]': 'date' +}; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ + +function getType (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library () { + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function (type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function (obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}],35:[function(require,module,exports){ +arguments[4][33][0].apply(exports,arguments) +},{"./lib/type":36,"dup":33}],36:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer <jake@alogicalparadox.com> + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ +var objectTypeRegexp = /^\[object (.*)\]$/; + +function getType(obj) { + var type = Object.prototype.toString.call(obj).match(objectTypeRegexp)[1].toLowerCase(); + // Let "new String('')" return 'object' + if (typeof Promise === 'function' && obj instanceof Promise) return 'promise'; + // PhantomJS has type "DOMWindow" for null + if (obj === null) return 'null'; + // PhantomJS has type "DOMWindow" for undefined + if (obj === undefined) return 'undefined'; + return type; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library() { + if (!(this instanceof Library)) return new Library(); + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function(type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function(obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}]},{},[1])(1) +}); \ No newline at end of file
diff --git a/third_party/leveldatabase/BUILD.gn b/third_party/leveldatabase/BUILD.gn index b3080d8..0057c0ee 100644 --- a/third_party/leveldatabase/BUILD.gn +++ b/third_party/leveldatabase/BUILD.gn
@@ -282,6 +282,13 @@ deps = [ ":leveldb_testutil", ] + + if (is_win) { + # db\log_test.cc(486) triggers two warnings: + # util\testharness.h(91): warning C4018: '<=': signed/unsigned mismatch + # util\testharness.h(89): warning C4018: '>=': signed/unsigned mismatch + cflags = [ "/wd4018" ] # Signed/unsigned mismatch in comparison. + } } test("leveldb_skiplist_test") {
diff --git a/third_party/libexif/BUILD.gn b/third_party/libexif/BUILD.gn index 3f88f1c9..ea9ca90 100644 --- a/third_party/libexif/BUILD.gn +++ b/third_party/libexif/BUILD.gn
@@ -57,11 +57,16 @@ # TODO(GYP): Additional options for non-Windows platforms. if (is_win) { - defines = [ - # This seems like a hack, but this is what WebKit Win does. - "snprintf=_snprintf", - "inline=__inline", - ] + import("//build/config/win/visual_studio_version.gni") + + if (visual_studio_version == "2013" || visual_studio_version == "2013e") { + defines = [ + # This seems like a hack, but this is what WebKit Win does. + # VS 2015 supports these natively so they cannot be #defines. + "snprintf=_snprintf", + "inline=__inline", + ] + } ldflags = [ "/DEF:" + rebase_path("libexif.def") ]
diff --git a/third_party/mesa/BUILD.gn b/third_party/mesa/BUILD.gn index 73be8e6..6ae815dd 100644 --- a/third_party/mesa/BUILD.gn +++ b/third_party/mesa/BUILD.gn
@@ -676,68 +676,59 @@ ] } -if (!is_android) { # TODO(GYP) enable for Android. - # Building this target will hide the native OpenGL shared library and - # replace it with a slow software renderer. - # - # Note: on x64 Windows this target gives warnings to the effect of: - # osmesa.osmesa.obj : warning LNK4197: export 'OSMesaGetIntegerv' specified - # multiple times; using first specification - # This also happens with the GYP build. - loadable_module("osmesa") { - sources = [ - "src/src/mesa/drivers/common/driverfuncs.c", - "src/src/mesa/drivers/common/driverfuncs.h", - "src/src/mesa/drivers/common/meta.c", - "src/src/mesa/drivers/common/meta.h", - "src/src/mesa/drivers/osmesa/osmesa.c", - ] +# Building this target will hide the native OpenGL shared library and +# replace it with a slow software renderer. +# +# Note: on x64 Windows this target gives warnings to the effect of: +# osmesa.osmesa.obj : warning LNK4197: export 'OSMesaGetIntegerv' specified +# multiple times; using first specification +# This also happens with the GYP build. +loadable_module("osmesa") { + sources = [ + "src/src/mesa/drivers/common/driverfuncs.c", + "src/src/mesa/drivers/common/driverfuncs.h", + "src/src/mesa/drivers/common/meta.c", + "src/src/mesa/drivers/common/meta.h", + "src/src/mesa/drivers/osmesa/osmesa.c", + ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ - ":mesa_headers_config", - "//build/config/compiler:no_chromium_code", - ] - previous_configs = configs - configs = [] - configs = [ ":mesa_internal_config" ] + previous_configs + - [ ":mesa_internal_warnings" ] + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + ":mesa_headers_config", + "//build/config/compiler:no_chromium_code", + ] + previous_configs = configs + configs = [] + configs = [ ":mesa_internal_config" ] + previous_configs + + [ ":mesa_internal_warnings" ] - include_dirs = [ "src/src/mesa/drivers" ] + include_dirs = [ "src/src/mesa/drivers" ] - if (is_clang) { - # Mesa triggers some of these Clang warnings. - configs -= [ "//build/config/clang:extra_warnings" ] - } - - if (is_win) { - ldflags = - [ "/DEF:" + rebase_path("src/src/mesa/drivers/osmesa/osmesa.def", - root_build_dir) ] - } - - deps = [ - ":mesa", - ":mesa_headers", - ":mesa_libglslcommon", - "//build/config/sanitizers:deps", - ] - - if (is_win) { - defines = [ - "BUILD_GL32", - "KEYWORD1=GLAPI", - "KEYWORD2=GLAPIENTRY", - ] - } + if (is_clang) { + # Mesa triggers some of these Clang warnings. + configs -= [ "//build/config/clang:extra_warnings" ] } -} else { - # Placeholder to allow targets to unconditionally depend on this. - group("osmesa") { - } -} # !is_android -# TODO(GYP) Android osmesa_in_lib_dir target. + if (is_win) { + ldflags = [ "/DEF:" + rebase_path("src/src/mesa/drivers/osmesa/osmesa.def", + root_build_dir) ] + } + + deps = [ + ":mesa", + ":mesa_headers", + ":mesa_libglslcommon", + "//build/config/sanitizers:deps", + ] + + if (is_win) { + defines = [ + "BUILD_GL32", + "KEYWORD1=GLAPI", + "KEYWORD2=GLAPIENTRY", + ] + } +} if (is_linux) { config("wayland_drm_protocol_config") {
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium index 3aca540d..1d49bdd 100644 --- a/third_party/qcms/README.chromium +++ b/third_party/qcms/README.chromium
@@ -119,6 +119,8 @@ - https://code.google.com/p/chromium/issues/detail?id=532910 - Allow negative XYZ for display profiles on the APPLE port - https://code.google.com/p/chromium/issues/detail?id=562951 + - Add a color profile white point transform api + - https://code.google.com/p/chromium/issues/detail?id=564355 For the Chromium changes, since the import, in a patch format run: git diff b8456f38 src
diff --git a/third_party/qcms/src/chain.c b/third_party/qcms/src/chain.c index aa8506e4..5255070 100644 --- a/third_party/qcms/src/chain.c +++ b/third_party/qcms/src/chain.c
@@ -897,6 +897,7 @@ { struct qcms_modular_transform *first_transform = NULL; struct qcms_modular_transform **next_transform = &first_transform; + qcms_bool transform_to_pcs_xyz_only = (out == NULL); if (in->color_space == RGB_SIGNATURE) { struct qcms_modular_transform* rgb_to_pcs; @@ -909,7 +910,7 @@ goto fail; } - if (in->pcs == LAB_SIGNATURE && out->pcs == XYZ_SIGNATURE) { + if (in->pcs == LAB_SIGNATURE && (transform_to_pcs_xyz_only || out->pcs == XYZ_SIGNATURE)) { struct qcms_modular_transform* lab_to_pcs; lab_to_pcs = qcms_modular_transform_alloc(); if (!lab_to_pcs) @@ -918,6 +919,9 @@ lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_XYZ; } + if (transform_to_pcs_xyz_only) + return first_transform; + // This does not improve accuracy in practice, something is wrong here. //if (in->chromaticAdaption.invalid == false) { // struct qcms_modular_transform* chromaticAdaption; @@ -992,3 +996,31 @@ } return NULL; } + +qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]) +{ + const float inverse_internal_scale = 1.999969482421875f; + + // Set the output profile to NULL to request a color transform to PCS XYZ only. + struct qcms_modular_transform *transform_list = qcms_modular_transform_create(profile, NULL); + + // Now calculate how the profile transforms white input color to PCS XYZ space. + if (transform_list != NULL) { + XYZ[0] = XYZ[1] = XYZ[2] = 1.0f; // white input + qcms_modular_transform_data(transform_list, XYZ, XYZ, 1); + // qcms_modular_transform_create internally scales input by 1/1.999969482421875f + // but no qcms changelog describes why / how that number was choosen. junov@ "it + // might be related to the epsilon of the fixed-point type 2*(1-1/(2^16)), but + // there is no explanation, which is disconcerting." Meanwhile, undo the internal + // scaling so we return a normalized CIEXYZ value viz., where Y is scaled to 1.0. + // A properly created color profile should produce Y=~1.0 in PCS XYZ with white + // input (the D50 test). If it does not, then the profile is likely bogus. + XYZ[0] *= inverse_internal_scale; + XYZ[1] *= inverse_internal_scale; + XYZ[2] *= inverse_internal_scale; + qcms_modular_transform_release(transform_list); + return true; + } + + return false; +}
diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h index 19958fd0..efe5cd64 100644 --- a/third_party/qcms/src/qcms.h +++ b/third_party/qcms/src/qcms.h
@@ -114,6 +114,7 @@ qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); qcms_color_space qcms_profile_get_color_space(qcms_profile *profile); unsigned qcms_profile_get_version(qcms_profile *profile); +qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]); qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); const char* qcms_profile_get_description(qcms_profile *profile);
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index aca7cb9a..d59ae27 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -3,8 +3,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Windows can't run .sh files, so this is a Python implementation of -update.sh. This script should replace update.sh on all platforms eventually.""" +"""This script is used to download prebuilt clang binaries. + +It is also used by package.py to build the prebuilt clang binaries.""" import argparse import cStringIO @@ -26,7 +27,6 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://code.google.com/p/chromium/wiki/UpdatingClang # Reverting problematic clang rolls is safe, though. -# Note: this revision is only used for Windows. Other platforms use update.sh. CLANG_REVISION = '254049' use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ @@ -301,9 +301,17 @@ def UpdateClang(args): print 'Updating Clang to %s...' % PACKAGE_VERSION + + need_gold_plugin = 'LLVM_DOWNLOAD_GOLD_PLUGIN' in os.environ or ( + sys.platform.startswith('linux') and + 'buildtype=Official' in os.environ.get('GYP_DEFINES', '') and + 'branding=Chrome' in os.environ.get('GYP_DEFINES', '')) + if ReadStampFile() == PACKAGE_VERSION: - print 'Already up to date.' - return 0 + print 'Clang is already up to date.' + if not need_gold_plugin or os.path.exists( + os.path.join(LLVM_BUILD_DIR, "lib/LLVMgold.so")): + return 0 # Reset the stamp file in case the build is unsuccessful. WriteStampFile('') @@ -331,10 +339,7 @@ # Download the gold plugin if requested to by an environment variable. # This is used by the CFI ClusterFuzz bot, and it's required for official # builds on linux. - if 'LLVM_DOWNLOAD_GOLD_PLUGIN' in os.environ or ( - sys.platform.startswith('linux') and - 'buildtype=Official' in os.environ.get('GYP_DEFINES', '') and - 'branding=Chrome' in os.environ.get('GYP_DEFINES', '')): + if need_gold_plugin: RunCommand(['python', CHROMIUM_DIR+'/build/download_gold_plugin.py']) WriteStampFile(PACKAGE_VERSION) return 0
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index ed4191251..536e640 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -8107,6 +8107,35 @@ <description>User opened the app menu.</description> </action> +<action name="MobileNTP.Snippets.Click"> + <owner>knn@chromium.org</owner> + <description> + Android: User clicked on a snippet card into the host website. + </description> +</action> + +<action name="MobileNTP.Snippets.Scrolled"> + <owner>knn@chromium.org</owner> + <description> + Android: User scrolled through the snippet cards. Recorded at the beginning + of the scroll event. + </description> +</action> + +<action name="MobileNTP.Snippets.ShowLess"> + <owner>knn@chromium.org</owner> + <description> + Android: User clicked on a snippet card to hide the bigger summary. + </description> +</action> + +<action name="MobileNTP.Snippets.ShowMore"> + <owner>knn@chromium.org</owner> + <description> + Android: User clicked on a snippet card to reveal a bigger summary. + </description> +</action> + <action name="MobileNTPBookmark"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 90399295..d8e09df 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -10591,6 +10591,23 @@ </summary> </histogram> +<histogram name="Event.Latency.HitTest" units="microseconds"> + <owner>dtapuska@chromium.org</owner> + <summary> + Duration of a non-resurive hitTest operation. The hit test is non-recursive + when the AllowChildFrameContent flag is clear. See also + Event.Latency.HitTestRecusrive. + </summary> +</histogram> + +<histogram name="Event.Latency.HitTestRecursive" units="microseconds"> + <owner>dtapuska@chromium.org</owner> + <summary> + Duration of a recursive hitTest operation. The hit test is recursive when + the AllowChildFrameContent flag is set. See also Event.Latency.HitTest. + </summary> +</histogram> + <histogram name="Event.Latency.Renderer" units="microseconds"> <owner>rbyers@chromium.org</owner> <summary> @@ -29638,6 +29655,55 @@ </summary> </histogram> +<histogram name="NewTabPage.Snippets.CardClicked"> + <owner>knn@chromium.org</owner> + <summary> + Android: The position of the snippets card on the NTP, that is clicked + through to the host website of the content. + </summary> +</histogram> + +<histogram name="NewTabPage.Snippets.CardExpanded"> + <owner>knn@chromium.org</owner> + <summary> + Android: The position of the snippets card on the NTP, that is expanded to + reveal more content. + </summary> +</histogram> + +<histogram name="NewTabPage.Snippets.CardHidden"> + <owner>knn@chromium.org</owner> + <summary> + Android: The position of the snippets card on the NTP, for which the + expanded content was minimized/hidden. + </summary> +</histogram> + +<histogram name="NewTabPage.Snippets.CardShown"> + <owner>knn@chromium.org</owner> + <summary> + Android: The position of the snippets card that is shown on the NTP. + Depending on the device screen size only some of the cards will be shown + unless the users scrolls through. + </summary> +</histogram> + +<histogram name="NewTabPage.Snippets.Interactions" enum="SnippetsInteractions"> + <owner>knn@chromium.org</owner> + <summary> + Android: A histogram giving an overall summary of important events like + impressions, scroll events, clicks etc. + </summary> +</histogram> + +<histogram name="NewTabPage.Snippets.NumArticles"> + <owner>knn@chromium.org</owner> + <summary> + Android: The number of snippet articles available to show on the NTP logged + once per NTP load. + </summary> +</histogram> + <histogram name="NewTabPage.SuggestedSite"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -66432,7 +66498,7 @@ <int value="24" label="NETWORK_INVALID_REQUEST"/> <int value="30" label="SERVER_FAILED"/> <int value="31" label="SERVER_NO_RANGE"/> - <int value="32" label="SERVER_PRECONDITION"/> + <int value="32" label="SERVER_PRECONDITION (Deprecated)"/> <int value="33" label="SERVER_BAD_CONTENT"/> <int value="34" label="SERVER_UNAUTHORIZED"/> <int value="35" label="SERVER_CERT_PROBLEM"/> @@ -70057,6 +70123,7 @@ <int value="4" label="802.11n"/> <int value="5" label="PSB 10MHz-wide"/> <int value="6" label="PSB 5MHz-wide"/> + <int value="7" label="802.11ac"/> </enum> <enum name="NetworkPortalResult" type="int"> @@ -75326,6 +75393,12 @@ <int value="4" label="Others"/> </enum> +<enum name="SnippetsInteractions" type="int"> + <int value="0" label="Snippets were shown to the user"/> + <int value="1" label="User scrolled through the snippets"/> + <int value="2" label="User clicked on a snippet into the host website"/> +</enum> + <enum name="SocketStreamConnectionType" type="int"> <int value="0" label="None"/> <int value="1" label="All"/>
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index caeab27..6a1b7485 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -21,7 +21,7 @@ ] if (is_win) { - data_deps += [ "//content/shell:crash_service" ] + data_deps += [ "//chrome/tools/crash_service" ] data += [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] }
diff --git a/tools/perf/run_benchmark b/tools/perf/run_benchmark index 8f7a8a91a..f7db394 100755 --- a/tools/perf/run_benchmark +++ b/tools/perf/run_benchmark
@@ -6,7 +6,7 @@ import sys from core import path_util -sys.path.append(path_util.GetTelemetryDir()) +sys.path.insert(1, path_util.GetTelemetryDir()) from telemetry import benchmark_runner
diff --git a/tools/telemetry/telemetry/core/platform_unittest.py b/tools/telemetry/telemetry/core/platform_unittest.py index 409d869..ad46250 100644 --- a/tools/telemetry/telemetry/core/platform_unittest.py +++ b/tools/telemetry/telemetry/core/platform_unittest.py
@@ -18,6 +18,7 @@ # Run this test in serial to avoid multiple browsers pop up on the screen. @decorators.Isolated + @decorators.Disabled('linux') # crbug.com/563656 def testScreenshot(self): if not self._platform.CanTakeScreenshot(): self.skipTest('Platform does not support screenshots, skipping test.')
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt index f73f0fd..be53b7c3 100644 --- a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt
@@ -32,8 +32,6 @@ MDnsTest.RefreshQuery # http://crbug.com/557993 -ProxyResolverV8TracingWrapperTest.Terminate ProxyResolverV8TracingTest.Terminate - -# http://crbug.com/562414 -NetworkQualityEstimatorTest.TestGetMedianRTTSince +ProxyResolverV8TracingWrapperTest.Dns +ProxyResolverV8TracingWrapperTest.Terminate \ No newline at end of file
diff --git a/ui/app_list/search/history_data_store_unittest.cc b/ui/app_list/search/history_data_store_unittest.cc index 26890f4..6af4dc0 100644 --- a/ui/app_list/search/history_data_store_unittest.cc +++ b/ui/app_list/search/history_data_store_unittest.cc
@@ -9,7 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/test/sequenced_worker_pool_owner.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/app_list/search/dictionary_data_store.h" #include "ui/app_list/search/history_data.h" @@ -41,12 +41,10 @@ class HistoryDataStoreTest : public testing::Test { public: - HistoryDataStoreTest() {} - ~HistoryDataStoreTest() override {} + HistoryDataStoreTest() : worker_pool_owner_(1, "AppLanucherTest") {} // testing::Test overrides: void SetUp() override { - worker_pool_ = new base::SequencedWorkerPool(1, "AppLauncherTest"); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } void TearDown() override { @@ -57,7 +55,7 @@ void OpenStore(const std::string& file_name) { data_file_ = temp_dir_.path().AppendASCII(file_name); store_ = new HistoryDataStore(scoped_refptr<DictionaryDataStore>( - new DictionaryDataStore(data_file_, worker_pool_.get()))); + new DictionaryDataStore(data_file_, worker_pool_owner_.pool().get()))); Load(); } @@ -95,7 +93,7 @@ base::ScopedTempDir temp_dir_; base::FilePath data_file_; scoped_ptr<base::RunLoop> run_loop_; - scoped_refptr<base::SequencedWorkerPool> worker_pool_; + base::SequencedWorkerPoolOwner worker_pool_owner_; scoped_refptr<HistoryDataStore> store_; HistoryData::Associations associations_;
diff --git a/ui/base/ime/win/tsf_input_scope.cc b/ui/base/ime/win/tsf_input_scope.cc index a1ba89a..4a75da0 100644 --- a/ui/base/ime/win/tsf_input_scope.cc +++ b/ui/base/ime/win/tsf_input_scope.cc
@@ -4,11 +4,10 @@ #include "ui/base/ime/win/tsf_input_scope.h" -#include <algorithm> - #include "base/compiler_specific.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/stl_util.h" #include "base/win/windows_version.h" namespace ui { @@ -22,8 +21,7 @@ if (input_scope == IS_DEFAULT) return; - if (std::find(input_scopes->begin(), input_scopes->end(), input_scope) != - input_scopes->end()) + if (ContainsValue(*input_scopes, input_scope)) return; input_scopes->push_back(input_scope);
diff --git a/ui/base/win/hwnd_subclass.cc b/ui/base/win/hwnd_subclass.cc index 6c9a70c..dd052445 100644 --- a/ui/base/win/hwnd_subclass.cc +++ b/ui/base/win/hwnd_subclass.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/memory/scoped_vector.h" #include "base/memory/singleton.h" +#include "base/stl_util.h" #include "ui/gfx/win/dpi.h" #include "ui/gfx/win/hwnd_util.h" @@ -109,7 +110,7 @@ void HWNDSubclass::AddFilter(HWNDMessageFilter* filter) { DCHECK(filter); - if (std::find(filters_.begin(), filters_.end(), filter) == filters_.end()) + if (!ContainsValue(filters_, filter)) filters_.push_back(filter); }
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index b253a77..c8bc999 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc
@@ -27,6 +27,7 @@ #include "base/memory/singleton.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -558,10 +559,8 @@ std::vector<XAtom> wm_states; if (GetAtomArrayProperty(window, "_NET_WM_STATE", &wm_states)) { XAtom hidden_atom = GetAtom("_NET_WM_STATE_HIDDEN"); - if (std::find(wm_states.begin(), wm_states.end(), hidden_atom) != - wm_states.end()) { + if (ContainsValue(wm_states, hidden_atom)) return false; - } } // Some compositing window managers (notably kwin) do not actually unmap
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index 71b0c8e..ecbfa2b8 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -118,6 +118,8 @@ "gestures/gesture_types.h", "null_event_targeter.cc", "null_event_targeter.h", + "scoped_target_handler.cc", + "scoped_target_handler.h", "win/events_win.cc", "win/system_event_state_lookup.cc", "win/system_event_state_lookup.h", @@ -353,6 +355,7 @@ "keycodes/keyboard_code_conversion_unittest.cc", "latency_info_unittest.cc", "platform/platform_event_source_unittest.cc", + "scoped_target_handler_unittest.cc", ] deps = [
diff --git a/ui/events/blink/input_scroll_elasticity_controller.cc b/ui/events/blink/input_scroll_elasticity_controller.cc index bdd1808..5663a9ce 100644 --- a/ui/events/blink/input_scroll_elasticity_controller.cc +++ b/ui/events/blink/input_scroll_elasticity_controller.cc
@@ -265,7 +265,11 @@ if (!CanScrollVertically()) momentum_animation_initial_velocity_.set_y(0); - helper_->RequestAnimate(); + // TODO(crbug.com/394562): This can go away once input is batched to the front + // of the frame? Then Animate() would always happen after this, so it would + // have a chance to tick the animation there and would return if any + // animations were active. + helper_->RequestOneBeginFrame(); } void InputScrollElasticityController::Animate(base::TimeTicks time) { @@ -320,7 +324,9 @@ stretch_scroll_force_ = StretchScrollForceForStretchAmount(new_stretch_amount); helper_->SetStretchAmount(new_stretch_amount); - helper_->RequestAnimate(); + // TODO(danakj): Make this a return value back to the compositor to have it + // schedule another frame and/or a draw. (Also, crbug.com/551138.) + helper_->RequestOneBeginFrame(); } bool InputScrollElasticityController::PinnedHorizontally(
diff --git a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc index 51fe4ff..82b9434 100644 --- a/ui/events/blink/input_scroll_elasticity_controller_unittest.cc +++ b/ui/events/blink/input_scroll_elasticity_controller_unittest.cc
@@ -26,7 +26,7 @@ MockScrollElasticityHelper() : is_user_scrollable_(true), set_stretch_amount_count_(0), - request_animate_count_(0) {} + request_begin_frame_count_(0) {} ~MockScrollElasticityHelper() override {} // cc::ScrollElasticityHelper implementation: @@ -43,10 +43,10 @@ void ScrollBy(const gfx::Vector2dF& delta) override { scroll_offset_ += gfx::ScrollOffset(delta); } - void RequestAnimate() override { request_animate_count_ += 1; } + void RequestOneBeginFrame() override { request_begin_frame_count_ += 1; } // Counters for number of times functions were called. - int request_animate_count() const { return request_animate_count_; } + int request_begin_frame_count() const { return request_begin_frame_count_; } int set_stretch_amount_count() const { return set_stretch_amount_count_; } void SetScrollOffsetAndMaxScrollOffset( @@ -63,7 +63,7 @@ bool is_user_scrollable_; gfx::Vector2dF stretch_amount_; int set_stretch_amount_count_; - int request_animate_count_; + int request_begin_frame_count_; gfx::ScrollOffset scroll_offset_; gfx::ScrollOffset max_scroll_offset_; @@ -131,7 +131,7 @@ helper_.SetStretchAmount(gfx::Vector2dF()); EXPECT_EQ(2, helper_.set_stretch_amount_count()); SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(0, helper_.request_animate_count()); + EXPECT_EQ(0, helper_.request_begin_frame_count()); // If we push more in the X direction than the Y direction, we should see a // stretch only in the X direction. This decision should be based on the @@ -145,7 +145,7 @@ helper_.SetStretchAmount(gfx::Vector2dF()); EXPECT_EQ(4, helper_.set_stretch_amount_count()); SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(0, helper_.request_animate_count()); + EXPECT_EQ(0, helper_.request_begin_frame_count()); } // Verify that we need a total overscroll delta of at least 10 in a pinned @@ -196,9 +196,9 @@ // End the gesture. Because there is a non-zero stretch, we should be in the // animated state, and should have had a frame requested. - EXPECT_EQ(0, helper_.request_animate_count()); + EXPECT_EQ(0, helper_.request_begin_frame_count()); SendMouseWheelEvent(PhaseEnded, PhaseNone); - EXPECT_EQ(1, helper_.request_animate_count()); + EXPECT_EQ(1, helper_.request_begin_frame_count()); } // Verify that an stretch caused by a momentum scroll will switch to the @@ -233,14 +233,14 @@ SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -8)); EXPECT_EQ(0, helper_.set_stretch_amount_count()); - EXPECT_EQ(0, helper_.request_animate_count()); + EXPECT_EQ(0, helper_.request_begin_frame_count()); // Take another step, this time going over the threshold. This should update // the stretch amount, and then switch to the animating mode. SendMouseWheelEvent(PhaseNone, PhaseChanged, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(1, helper_.request_animate_count()); + EXPECT_EQ(1, helper_.request_begin_frame_count()); EXPECT_GT(-1.f, helper_.StretchAmount().y()); // Subsequent momentum events should do nothing. @@ -251,50 +251,50 @@ SendMouseWheelEvent(PhaseNone, PhaseEnded, gfx::Vector2dF(0, -80), gfx::Vector2dF(0, -80)); EXPECT_EQ(1, helper_.set_stretch_amount_count()); - EXPECT_EQ(1, helper_.request_animate_count()); + EXPECT_EQ(1, helper_.request_begin_frame_count()); // Subsequent animate events should update the stretch amount and request // another frame. TickCurrentTimeAndAnimate(); EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(2, helper_.request_animate_count()); + EXPECT_EQ(2, helper_.request_begin_frame_count()); EXPECT_GT(-1.f, helper_.StretchAmount().y()); // Touching the trackpad (a PhaseMayBegin event) should disable animation. SendMouseWheelEvent(PhaseMayBegin, PhaseNone); TickCurrentTimeAndAnimate(); EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(2, helper_.request_animate_count()); + EXPECT_EQ(2, helper_.request_begin_frame_count()); // Releasing the trackpad should re-enable animation. SendMouseWheelEvent(PhaseCancelled, PhaseNone); EXPECT_EQ(2, helper_.set_stretch_amount_count()); - EXPECT_EQ(3, helper_.request_animate_count()); + EXPECT_EQ(3, helper_.request_begin_frame_count()); TickCurrentTimeAndAnimate(); EXPECT_EQ(3, helper_.set_stretch_amount_count()); - EXPECT_EQ(4, helper_.request_animate_count()); + EXPECT_EQ(4, helper_.request_begin_frame_count()); // Keep animating frames until the stretch returns to rest. int stretch_count = 3; - int animate_count = 4; + int begin_frame_count = 4; while (1) { TickCurrentTimeAndAnimate(); if (helper_.StretchAmount().IsZero()) { stretch_count += 1; EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); + EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); break; } stretch_count += 1; - animate_count += 1; + begin_frame_count += 1; EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); + EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); } // After coming to rest, no subsequent animate calls change anything. TickCurrentTimeAndAnimate(); EXPECT_EQ(stretch_count, helper_.set_stretch_amount_count()); - EXPECT_EQ(animate_count, helper_.request_animate_count()); + EXPECT_EQ(begin_frame_count, helper_.request_begin_frame_count()); } // Verify that an stretch opposing a scroll is correctly resolved.
diff --git a/ui/events/events.gyp b/ui/events/events.gyp index 82cd006..757324b 100644 --- a/ui/events/events.gyp +++ b/ui/events/events.gyp
@@ -146,6 +146,8 @@ 'linux/text_edit_key_bindings_delegate_auralinux.h', 'null_event_targeter.cc', 'null_event_targeter.h', + 'scoped_target_handler.cc', + 'scoped_target_handler.h', 'ozone/events_ozone.cc', 'win/events_win.cc', 'win/system_event_state_lookup.cc',
diff --git a/ui/events/events_unittests.gyp b/ui/events/events_unittests.gyp index f7e5a67..e2979669 100644 --- a/ui/events/events_unittests.gyp +++ b/ui/events/events_unittests.gyp
@@ -59,6 +59,7 @@ 'keycodes/keyboard_code_conversion_unittest.cc', 'latency_info_unittest.cc', 'platform/platform_event_source_unittest.cc', + 'scoped_target_handler_unittest.cc', 'x/events_x_unittest.cc', ], 'include_dirs': [
diff --git a/ui/events/scoped_target_handler.cc b/ui/events/scoped_target_handler.cc new file mode 100644 index 0000000..08608b4 --- /dev/null +++ b/ui/events/scoped_target_handler.cc
@@ -0,0 +1,44 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/scoped_target_handler.h" + +#include "ui/events/event.h" +#include "ui/events/event_handler.h" +#include "ui/events/event_target.h" + +namespace ui { + +ScopedTargetHandler::ScopedTargetHandler(EventTarget* target, + EventHandler* handler) + : destroyed_flag_(NULL), target_(target), new_handler_(handler) { + original_handler_ = target_->SetTargetHandler(this); +} + +ScopedTargetHandler::~ScopedTargetHandler() { + EventHandler* handler = target_->SetTargetHandler(original_handler_); + DCHECK_EQ(this, handler); + if (destroyed_flag_) + *destroyed_flag_ = true; +} + +void ScopedTargetHandler::OnEvent(Event* event) { + if (original_handler_) { + bool destroyed = false; + bool* old_destroyed_flag = destroyed_flag_; + destroyed_flag_ = &destroyed; + + original_handler_->OnEvent(event); + + if (destroyed) { + if (old_destroyed_flag) + *old_destroyed_flag = true; + return; + } + destroyed_flag_ = old_destroyed_flag; + } + new_handler_->OnEvent(event); +} + +} // namespace ui
diff --git a/ui/events/scoped_target_handler.h b/ui/events/scoped_target_handler.h new file mode 100644 index 0000000..98d8574 --- /dev/null +++ b/ui/events/scoped_target_handler.h
@@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_SCOPED_TARGET_HANDLER_H_ +#define UI_EVENTS_SCOPED_TARGET_HANDLER_H_ + +#include "base/macros.h" +#include "ui/events/event_handler.h" +#include "ui/events/events_export.h" + +namespace ui { + +class EventTarget; + +// An EventHandler that replaces an EventTarget's target handler with itself to +// pass events first to the original handler and second to an additional new +// EventHandler. The new handler gets called after the original handler even +// if it calls SetHandled() or StopPropagation() on the event. +class EVENTS_EXPORT ScopedTargetHandler : public EventHandler { + public: + ScopedTargetHandler(EventTarget* target, EventHandler* new_handler); + ~ScopedTargetHandler() override; + + // EventHandler: + void OnEvent(Event* event) override; + + private: + // If non-null the destructor sets this to true. This is set while handling + // an event and used to detect if |this| has been deleted. + bool* destroyed_flag_; + + // An EventTarget that has its target handler replaced with |this| for a life + // time of |this|. + EventTarget* target_; + + // An EventHandler that gets restored on |view_| when |this| is destroyed. + EventHandler* original_handler_; + + // A new handler that gets events in addition to the |original_handler_|. + EventHandler* new_handler_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTargetHandler); +}; + +} // namespace ui + +#endif // UI_EVENTsS_SCOPED_TARGET_HANDLER_H_
diff --git a/ui/events/scoped_target_handler_unittest.cc b/ui/events/scoped_target_handler_unittest.cc new file mode 100644 index 0000000..b8c8d78 --- /dev/null +++ b/ui/events/scoped_target_handler_unittest.cc
@@ -0,0 +1,206 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/scoped_target_handler.h" + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event_handler.h" +#include "ui/events/event_target.h" +#include "ui/events/event_target_iterator.h" +#include "ui/events/event_utils.h" + +namespace ui { + +namespace { + +class TestEventTargetIterator : public EventTargetIterator { + public: + TestEventTargetIterator() {} + + // EventTargetIterator: + EventTarget* GetNextTarget() override { return nullptr; } + +private: + DISALLOW_COPY_AND_ASSIGN(TestEventTargetIterator); +}; + +// An EventTarget that holds ownership of its target and delegate EventHandlers. +class TestEventTarget : public EventTarget { + public: + TestEventTarget() {} + ~TestEventTarget() override {} + + void SetHandler(scoped_ptr<EventHandler> target_handler, + scoped_ptr<EventHandler> delegate) { + target_handler_ = target_handler.Pass(); + delegate_ = delegate.Pass(); + } + + // EventTarget: + void DispatchEvent(Event* event) { target_handler()->OnEvent(event); } + bool CanAcceptEvent(const Event& event) override { return true; } + EventTarget* GetParentTarget() override { return nullptr; } + scoped_ptr<EventTargetIterator> GetChildIterator() const override { + return make_scoped_ptr(new TestEventTargetIterator); + } + EventTargeter* GetEventTargeter() override { return nullptr; } + + private: + scoped_ptr<EventHandler> target_handler_; + scoped_ptr<EventHandler> delegate_; + + DISALLOW_COPY_AND_ASSIGN(TestEventTarget); +}; + +// An EventHandler that sets itself as a target handler for an EventTarget and +// can recursively dispatch an Event. +class NestedEventHandler : public EventHandler { + public: + NestedEventHandler(TestEventTarget* target, int nesting) + : target_(target), nesting_(nesting) { + original_handler_ = target_->SetTargetHandler(this); + } + ~NestedEventHandler() override { + EventHandler* handler = target_->SetTargetHandler(original_handler_); + DCHECK_EQ(this, handler); + } + + protected: + void OnEvent(Event* event) override { + if (--nesting_ == 0) + return; + target_->DispatchEvent(event); + } + + private: + TestEventTarget* target_; + int nesting_; + EventHandler* original_handler_; + + DISALLOW_COPY_AND_ASSIGN(NestedEventHandler); +}; + +// An EventHandler that sets itself as a target handler for an EventTarget and +// destroys that EventTarget when handling an Event, possibly after recursively +// handling the Event. +class TargetDestroyingEventHandler : public EventHandler { + public: + TargetDestroyingEventHandler(TestEventTarget* target, int nesting) + : target_(target), nesting_(nesting) { + original_handler_ = target_->SetTargetHandler(this); + } + ~TargetDestroyingEventHandler() override { + EventHandler* handler = target_->SetTargetHandler(original_handler_); + DCHECK_EQ(this, handler); + } + + protected: + void OnEvent(Event* event) override { + if (--nesting_ == 0) { + delete target_; + return; + } + target_->DispatchEvent(event); + } + + private: + TestEventTarget* target_; + int nesting_; + EventHandler* original_handler_; + + DISALLOW_COPY_AND_ASSIGN(TargetDestroyingEventHandler); +}; + +// An EventHandler that can be set to receive events in addition to the target +// handler and counts the Events that it receives. +class EventCountingEventHandler : public EventHandler { + public: + EventCountingEventHandler(EventTarget* target, int* count) + : scoped_target_handler_(new ScopedTargetHandler(target, this)), + count_(count) {} + ~EventCountingEventHandler() override {} + + protected: + void OnEvent(Event* event) override { (*count_)++; } + + private: + scoped_ptr<ScopedTargetHandler> scoped_target_handler_; + int* count_; + + DISALLOW_COPY_AND_ASSIGN(EventCountingEventHandler); +}; + +} // namespace + +// Tests that a ScopedTargetHandler invokes both the target and a delegate. +TEST(ScopedTargetHandlerTest, HandlerInvoked) { + int count = 0; + TestEventTarget* target = new TestEventTarget; + scoped_ptr<NestedEventHandler> target_handler( + new NestedEventHandler(target, 1)); + scoped_ptr<EventCountingEventHandler> delegate( + new EventCountingEventHandler(target, &count)); + target->SetHandler(target_handler.Pass(), delegate.Pass()); + MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + EventTimeForNow(), EF_LEFT_MOUSE_BUTTON, + EF_LEFT_MOUSE_BUTTON); + target->DispatchEvent(&event); + EXPECT_EQ(1, count); + delete target; +} + +// Tests that a ScopedTargetHandler invokes both the target and a delegate when +// an Event is dispatched recursively such as with synthetic events. +TEST(ScopedTargetHandlerTest, HandlerInvokedNested) { + int count = 0; + TestEventTarget* target = new TestEventTarget; + scoped_ptr<NestedEventHandler> target_handler( + new NestedEventHandler(target, 2)); + scoped_ptr<EventCountingEventHandler> delegate( + new EventCountingEventHandler(target, &count)); + target->SetHandler(target_handler.Pass(), delegate.Pass()); + MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + EventTimeForNow(), EF_LEFT_MOUSE_BUTTON, + EF_LEFT_MOUSE_BUTTON); + target->DispatchEvent(&event); + EXPECT_EQ(2, count); + delete target; +} + +// Tests that a it is safe to delete a ScopedTargetHandler while handling an +// event. +TEST(ScopedTargetHandlerTest, SafeToDestroy) { + int count = 0; + TestEventTarget* target = new TestEventTarget; + scoped_ptr<TargetDestroyingEventHandler> target_handler( + new TargetDestroyingEventHandler(target, 1)); + scoped_ptr<EventCountingEventHandler> delegate( + new EventCountingEventHandler(target, &count)); + target->SetHandler(target_handler.Pass(), delegate.Pass()); + MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + EventTimeForNow(), EF_LEFT_MOUSE_BUTTON, + EF_LEFT_MOUSE_BUTTON); + target->DispatchEvent(&event); + EXPECT_EQ(0, count); +} + +// Tests that a it is safe to delete a ScopedTargetHandler while handling an +// event recursively. +TEST(ScopedTargetHandlerTest, SafeToDestroyNested) { + int count = 0; + TestEventTarget* target = new TestEventTarget; + scoped_ptr<TargetDestroyingEventHandler> target_handler( + new TargetDestroyingEventHandler(target, 2)); + scoped_ptr<EventCountingEventHandler> delegate( + new EventCountingEventHandler(target, &count)); + target->SetHandler(target_handler.Pass(), delegate.Pass()); + MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + EventTimeForNow(), EF_LEFT_MOUSE_BUTTON, + EF_LEFT_MOUSE_BUTTON); + target->DispatchEvent(&event); + EXPECT_EQ(0, count); +} + +} // namespace ui
diff --git a/ui/file_manager/audio_player/assets/100/player_button_volume_muted.png b/ui/file_manager/audio_player/assets/100/player_button_volume_muted.png new file mode 100644 index 0000000..72db204a3 --- /dev/null +++ b/ui/file_manager/audio_player/assets/100/player_button_volume_muted.png Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_volume_muted.png b/ui/file_manager/audio_player/assets/200/player_button_volume_muted.png new file mode 100644 index 0000000..211d1c9 --- /dev/null +++ b/ui/file_manager/audio_player/assets/200/player_button_volume_muted.png Binary files differ
diff --git a/ui/file_manager/audio_player/elements/audio_player.js b/ui/file_manager/audio_player/elements/audio_player.js index 6c1820f..df97719 100644 --- a/ui/file_manager/audio_player/elements/audio_player.js +++ b/ui/file_manager/audio_player/elements/audio_player.js
@@ -439,22 +439,6 @@ */ onKeyDown_: function(event) { switch (event.keyIdentifier) { - case 'Up': - if (this.$.audioController.volumeSliderShown && this.model.volume < 100) - this.model.volume += 1; - break; - case 'Down': - if (this.$.audioController.volumeSliderShown && this.model.volume > 0) - this.model.volume -= 1; - break; - case 'PageUp': - if (this.$.audioController.volumeSliderShown && this.model.volume < 91) - this.model.volume += 10; - break; - case 'PageDown': - if (this.$.audioController.volumeSliderShown && this.model.volume > 9) - this.model.volume -= 10; - break; case 'MediaNextTrack': this.onControllerNextClicked(); break;
diff --git a/ui/file_manager/audio_player/elements/control_panel.css b/ui/file_manager/audio_player/elements/control_panel.css index fd9a4a43..c4b6075 100644 --- a/ui/file_manager/audio_player/elements/control_panel.css +++ b/ui/file_manager/audio_player/elements/control_panel.css
@@ -34,6 +34,7 @@ .media-button { background-color: transparent; border: 0; + flex: none; height: 32px; outline: none; /* TODO(yoshiki): Show outline only on keyboard focus. */ padding: 0; @@ -59,13 +60,9 @@ top: 0; } -/* Custom sliders for progress and volume. */ +/* Time and volume controls. */ -/* Customize the standard input[type='range']. */ - -/* Time controls: a slider and a text time display. */ - -.time-controls { +.time-volume-controls { align-items: center; display: flex; flex-direction: row; @@ -73,7 +70,7 @@ justify-content: center; } -.time-controls > .time-container { +.time-volume-controls > .time-container { color: rgb(51, 51, 51); cursor: default; flex: none; @@ -96,12 +93,22 @@ opacity: 0; /* This class is intended to be used as invisible spacer. */ } -.time-controls > paper-slider { +.time-volume-controls > paper-slider { --paper-slider-active-color: rgb(66, 133, 244); --paper-slider-knob-color: rgb(64, 138, 241); flex: auto; } +#timeSlider { + flex: 3 1 auto; + width: 118px; +} + +#volumeSlider { + flex: 1 1 auto; + width: 82px; +} + .media-button.disabled, paper-slider.disabled { pointer-events: none; @@ -176,15 +183,6 @@ margin-right: 8px; } -.media-button.volume { - background-image: -webkit-image-set( - url(../assets/100/player_button_volume.png) 1x, - url(../assets/200/player_button_volume.png) 2x); - margin-left: 0; - margin-right: 8px; - pointer-events: auto; -} - .media-button.playlist { background-image: -webkit-image-set( url(../assets/100/player_button_playlist.png) 1x, @@ -192,6 +190,19 @@ pointer-events: auto; } +.media-button.volume { + background-image: -webkit-image-set( + url(../assets/100/player_button_volume.png) 1x, + url(../assets/200/player_button_volume.png) 2x); + pointer-events: auto; +} + +:host([volume='0']) .media-button.volume { + background-image: -webkit-image-set( + url(../assets/100/player_button_volume_muted.png) 1x, + url(../assets/200/player_button_volume_muted.png) 2x); +} + /* Invisible div used to compute the width required for the elapsed time. */ .time-controls > .time > .current { align-items: center; @@ -202,18 +213,3 @@ position: absolute; top: -1px; } - -/* Volume controls: sound button and volume slider */ - -#volumeContainer { - border: 1px solid #ddd; - border-radius: 2px; - box-shadow: 0 2px 4px #777; - height: 110px; - position: fixed; - width: 32px; -} - -#volumeContainer.default-hidden { - visibility: hidden; -}
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html index 6e9df26..e092b62 100644 --- a/ui/file_manager/audio_player/elements/control_panel.html +++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -7,7 +7,6 @@ <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/font-roboto/roboto.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html"> -<link rel="import" href="volume_controller.html"> <link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html"> <dom-module id="control-panel"> @@ -50,24 +49,6 @@ on-click="nextClick"> </files-icon-button> - <div id="volumeContainer" - class="default-hidden" - anchor-point="bottom center"> - <volume-controller id="volumeSlider" value="{{volume}}" - width="32" height="85" value="50"> - </volume-controller> - - <polymer-anchor-point id="anchorHelper"></polymer-anchor-point> - </div> - - <!-- Volume button in the bottom line. --> - <files-icon-button toggles - id="volumeButton" - class="volume media-button toggle" - anchor-point="bottom center" - active="{{volumeSliderShown}}"> - </files-icon-button> - <!-- Playlist button in the bottom line. --> <files-icon-button toggles id="playList" @@ -75,12 +56,21 @@ active="{{expanded}}"> </files-icon-button> </div> - <div class="lower-controls time-controls"> + <div class="lower-controls time-volume-controls"> + <!-- Play/pause button and seek slider in the bottom line. --> <div class="time-container"> <div class="time-spacer">[[computeTimeString_(duration, duration)]]</div> <div class="time">[[computeTimeString_(time, duration)]]</div> </div> <paper-slider id="timeSlider" max="[[duration]]" value="{{time::change}}"></paper-slider> + + <!-- Volume button and slider in the bottom line. --> + <files-icon-button + id="volumeButton" + class="volume media-button" + on-click="volumeClick"> + </files-icon-button> + <paper-slider id="volumeSlider"></paper-slider> </div> </div> </template>
diff --git a/ui/file_manager/audio_player/elements/control_panel.js b/ui/file_manager/audio_player/elements/control_panel.js index 452b881d..cf162100 100644 --- a/ui/file_manager/audio_player/elements/control_panel.js +++ b/ui/file_manager/audio_player/elements/control_panel.js
@@ -81,7 +81,9 @@ */ volume: { type: Number, - notify: true + notify: true, + reflectToAttribute: true, + observer: 'volumeChanged_' }, /** @@ -94,16 +96,6 @@ }, /** - * Whether the volume slider is expanded or not. - */ - volumeSliderShown: { - type: Boolean, - value: false, - observer: 'volumeSliderShownChanged', - notify: true - }, - - /** * Whether the knob of time slider is being dragged. */ dragging: { @@ -126,19 +118,26 @@ * element is ready. */ ready: function() { - var onFocusoutBound = this.onVolumeControllerFocusout_.bind(this); - - this.$.volumeSlider.addEventListener('focusout', onFocusoutBound); - this.$.volumeButton.addEventListener('focusout', onFocusoutBound); - - this.$.timeSlider.addEventListener('value-change', function() { + var timeSlider = /** @type {PaperSliderElement} */ (this.$.timeSlider); + timeSlider.addEventListener('change', function() { if (this.dragging) this.dragging = false; }.bind(this)); - this.$.timeSlider.addEventListener('immediate-value-change', function() { + timeSlider.addEventListener('immediate-value-change', function() { if (!this.dragging) this.dragging = true; }.bind(this)); + + // Update volume on user inputs for volume slider. + // During a drag operation, the volume should be updated immediately. + var volumeSlider = + /** @type {PaperSliderElement} */ (this.$.volumeSlider); + volumeSlider.addEventListener('change', function() { + this.volume = volumeSlider.value; + }.bind(this)); + volumeSlider.addEventListener('immediate-value-change', function() { + this.volume = volumeSlider.immediateValue; + }.bind(this)); }, /** @@ -163,40 +162,14 @@ }, /** - * Invoked when the property 'volumeSliderShown' changes. - * @param {boolean} shown + * Invoked when the volume button is clicked. */ - volumeSliderShownChanged: function(shown) { - this.showVolumeController_(shown); - }, - - /** - * Invoked when the focus goes out of the volume elements. - * @param {!UIEvent} event The focusout event. - * @private - */ - onVolumeControllerFocusout_: function(event) { - if (this.volumeSliderShown) { - // If the focus goes out of the volume, hide the volume control. - if (!event.relatedTarget || - (!this.$.volumeButton.contains(event.relatedTarget) && - !this.$.volumeSlider.contains(event.relatedTarget))) { - this.volumeSliderShown = false; - } - } - }, - - /** - * Shows/hides the volume controller. - * @param {boolean} show True to show the controller, false to hide. - * @private - */ - showVolumeController_: function(show) { - if (show) { - matchBottomLine(this.$.volumeContainer, this.$.volumeButton); - this.$.volumeContainer.style.visibility = 'visible'; + volumeClick: function() { + if (this.volume !== 0) { + this.savedVolume_ = this.volume; + this.volume = 0; } else { - this.$.volumeContainer.style.visibility = 'hidden'; + this.volume = this.savedVolume_ || 50; } }, @@ -232,6 +205,21 @@ }, /** + * Invoked when the volume property is changed. + * @param {number} volume + * @private + */ + volumeChanged_: function(volume) { + if (!this.$.volumeSlider.dragging) + this.$.volumeSlider.value = volume; + + if (this.ariaLabels) { + this.$.volumeButton.setAttribute('aria-label', + volume !== 0 ? this.ariaLabels.mute : this.ariaLabels.unmute); + } + }, + + /** * Invoked when the ariaLabels property is changed. * @param {Object} ariaLabels * @private @@ -249,6 +237,9 @@ this.$.volumeButton.setAttribute('aria-label', ariaLabels.volume); this.$.playList.setAttribute('aria-label', ariaLabels.playList); this.$.timeSlider.setAttribute('aria-label', ariaLabels.seekSlider); + this.$.volumeButton.setAttribute('aria-label', + this.volume !== 0 ? ariaLabels.mute : ariaLabels.unmute); + this.$.volumeSlider.setAttribute('aria-label', ariaLabels.volumeSlider); } }); })(); // Anonymous closure
diff --git a/ui/file_manager/audio_player/elements/volume_controller.css b/ui/file_manager/audio_player/elements/volume_controller.css deleted file mode 100644 index 4e6880e..0000000 --- a/ui/file_manager/audio_player/elements/volume_controller.css +++ /dev/null
@@ -1,52 +0,0 @@ -/* Copyright 2014 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -:host { - background: white; - display: block; - height: 100px; - position: relative; - width: 32px; -} - -#background { - height: 100%; /* will be overridden by javascript */ - left: 0; - position: absolute; - top: 0; - width: 100%; -} - -input[type='range'] { - -webkit-appearance: none !important; - -webkit-transform: rotate(90deg); - background: transparent; - outline: none; - position: absolute; - z-index: 1; -} - -input[type='range']::-webkit-slider-thumb { - -webkit-appearance: none; - -webkit-transform: rotate(-90deg); - background-image: -webkit-image-set( - url(../assets/100/player_timeline_handler.png) 1x, - url(../assets/200/player_timeline_handler.png) 2x); - background-position: 50% 50%; - background-repeat: no-repeat no-repeat; - height: 24px; - position: relative; - width: 24px; -} - -#bar { - background: #000; - bottom: 14px; - position: absolute; - top: 14px; -} - -#bar .filled { - background: #aaa; -}
diff --git a/ui/file_manager/audio_player/elements/volume_controller.html b/ui/file_manager/audio_player/elements/volume_controller.html deleted file mode 100644 index 1431716..0000000 --- a/ui/file_manager/audio_player/elements/volume_controller.html +++ /dev/null
@@ -1,23 +0,0 @@ -<!-- - -- Copyright 2015 The Chromium Authors. All rights reserved. - -- Use of this source code is governed by a BSD-style license that can be - -- found in the LICENSE file. - --> - -<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> - -<dom-module id="volume-controller"> - <link rel="import" type="css" href="volume_controller.css"> - <template> - <div id="background"></div> - <input name="rawValueInput" id="rawValueInput" touch-action="manipulation" - type="range" min="0" max="100" value="{{rawValue::input}}"> - <div id="bar"> - <div class="filled" style$="[[computeFilledStyle_(rawValue)]]"></div> - <div class="cap left"></div> - <div class="cap right"></div> - </div> - </template> -</dom-module> - -<script src="volume_controller.js"></script>
diff --git a/ui/file_manager/audio_player/elements/volume_controller.js b/ui/file_manager/audio_player/elements/volume_controller.js deleted file mode 100644 index ed00080..0000000 --- a/ui/file_manager/audio_player/elements/volume_controller.js +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(function() { - 'use strict'; - - Polymer({ - is: 'volume-controller', - - properties: { - /** - * Width of the element in pixels. Must be specified before ready() is - * called. Dynamic change is not supported. - * @type {number} - */ - width: { - type: Number, - value: 32 - }, - - /** - * Height of the element in pixels. Must be specified before ready() is - * called. Dynamic change is not supported. - * @type {number} - */ - height: { - type: Number, - value: 100 - }, - - /** - * Volume. 0 is silent, and 100 is maximum. - * @type {number} - */ - value: { - type: Number, - value: 50, - observer: 'valueChanged', - notify: true - }, - - /** - * Volume. 100 is silent, and 0 is maximum. - * @type {number} - */ - rawValue: { - type: Number, - value: 0, - observer: 'rawValueChanged', - notify: true - } - }, - - /** - * Initializes an element. This method is called automatically when the - * element is ready. - */ - ready: function() { - this.style.width = this.width + 'px'; - this.style.height = this.height + 'px'; - - this.rawValueInput = this.$.rawValueInput; - this.bar = this.$.bar; - - this.rawValueInput.style.width = this.height + 'px'; - this.rawValueInput.style.height = this.width + 'px'; - this.rawValueInput.style.webkitTransformOrigin = - (this.width / 2) + 'px ' + - (this.width / 2 - 2) + 'px'; - - var barLeft = (this.width / 2 - 1); - this.bar.style.left = barLeft + 'px'; - this.bar.style.right = barLeft + 'px'; - - this.addEventListener('keydown', this.onKeyDown_.bind(this)); - }, - - /** - * Invoked when the 'volume' value is changed. - * @param {number} newValue New value. - * @param {number} oldValue Old value. - */ - valueChanged: function(newValue, oldValue) { - if (oldValue != newValue) - this.rawValue = 100 - newValue; - }, - - /** - * Invoked when the 'rawValue' property is changed. - * @param {number} newValue New value. - * @param {number} oldValue Old value. - */ - rawValueChanged: function(newValue, oldValue) { - if (oldValue !== newValue) - this.value = 100 - newValue; - }, - - /** - * Invoked when the 'keydown' event is fired. - * @param {Event} event The event object. - */ - onKeyDown_: function(event) { - switch (event.keyIdentifier) { - // Prevents the default behavior. These key should be handled in - // <audio-player> element. - case 'Up': - case 'Down': - case 'PageUp': - case 'PageDown': - event.preventDefault(); - break; - } - }, - - /** - * Computes style for '.filled' element based on raw value. - * @return {string} - */ - computeFilledStyle_: function(rawValue) { - return 'height: ' + rawValue + '%;'; - } - }); -})(); // Anonymous closure
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js index e178163b..f07bb0d4e 100644 --- a/ui/file_manager/audio_player/js/audio_player.js +++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -66,16 +66,17 @@ strings['AUDIO_PLAYER_DEFAULT_ARTIST']; // Pass translated labels to the AudioPlayerElement. this.player_.ariaLabels = { - volumeSlider: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'], shuffle: strings['AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL'], repeat: strings['AUDIO_PLAYER_REPEAT_BUTTON_LABEL'], previous: strings['MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL'], play: strings['MEDIA_PLAYER_PLAY_BUTTON_LABEL'], pause: strings['MEDIA_PLAYER_PAUSE_BUTTON_LABEL'], next: strings['MEDIA_PLAYER_NEXT_BUTTON_LABEL'], - volume: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'], playList: strings['AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL'], - seekSlider: strings['MEDIA_PLAYER_SEEK_SLIDER_LABEL'] + seekSlider: strings['MEDIA_PLAYER_SEEK_SLIDER_LABEL'], + mute: strings['MEDIA_PLAYER_MUTE_BUTTON_LABEL'], + unmute: strings['MEDIA_PLAYER_UNMUTE_BUTTON_LABEL'], + volumeSlider: strings['MEDIA_PLAYER_VOLUME_SLIDER_LABEL'] }; }.bind(this));
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js index 587c0816..4a11a1a 100644 --- a/ui/file_manager/audio_player/js/background.js +++ b/ui/file_manager/audio_player/js/background.js
@@ -22,9 +22,9 @@ id: 'audio-player', type: 'panel', minHeight: 4 + 48 + 96, // 4px: border-top, 48px: track, 96px: controller - minWidth: 280, + minWidth: 320, height: 4 + 48 + 96, // collapsed - width: 280, + width: 320, frame: { color: '#fafafa' }
diff --git a/ui/file_manager/audio_player/js/compiled_resources.gyp b/ui/file_manager/audio_player/js/compiled_resources.gyp index 4c4486d..1902b6e 100644 --- a/ui/file_manager/audio_player/js/compiled_resources.gyp +++ b/ui/file_manager/audio_player/js/compiled_resources.gyp
@@ -50,6 +50,16 @@ 'variables': { 'depends': [ '../../../../third_party/jstemplate/compiled_resources.gyp:jstemplate', + '../../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/iron-a11y-keys-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-form-element-behavior/iron-form-element-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-range-behavior/iron-range-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-inky-focus-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js', '../../../webui/resources/js/cr.js', '../../../webui/resources/js/cr/event_target.js', '../../../webui/resources/js/cr/ui.js',
diff --git a/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.js b/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.js index 3620691..17b4742 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.js +++ b/ui/file_manager/file_manager/foreground/elements/files_toggle_ripple.js
@@ -42,7 +42,7 @@ this.performDeactivateAnimation_(); } - this.$.ripple.classList.toggle('activated', newValue); + this.$.ripple.classList.toggle('activated', !!newValue); }, /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 9b974c2..11f2dc6 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -437,7 +437,7 @@ this.parentTree_.metadataModel.notifyEntriesChanged([this.dirEntry_]); this.parentTree_.metadataModel.get([this.dirEntry_], ['shared']).then( function(metadata) { - icon.classList.toggle('shared', metadata[0] && metadata[0].shared); + icon.classList.toggle('shared', !!(metadata[0] && metadata[0].shared)); }); };
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js index 1764273..17164a1 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -1155,7 +1155,7 @@ iconDiv.style.backgroundImage = ''; // Back to the default image. if (li.classList.contains('directory')) - iconDiv.classList.toggle('shared', externalProps.shared); + iconDiv.classList.toggle('shared', !!externalProps.shared); }; /**
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd index 48bd372..8826ebc 100644 --- a/ui/file_manager/file_manager_resources.grd +++ b/ui/file_manager/file_manager_resources.grd
@@ -170,9 +170,6 @@ <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_CSS" file="audio_player/elements/track_list.css" flattenhtml="true" type="BINDATA" /> <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_HTML" file="audio_player/elements/track_list.html" type="BINDATA" /> <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_JS" file="audio_player/elements/track_list.js" type="BINDATA" /> - <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_CSS" file="audio_player/elements/volume_controller.css" flattenhtml="true" type="BINDATA" /> - <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_HTML" file="audio_player/elements/volume_controller.html" type="BINDATA" /> - <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_JS" file="audio_player/elements/volume_controller.js" type="BINDATA" /> <include name="IDR_AUDIO_PLAYER_METADATA_WORKER_JS" file="audio_player/js/metadata_worker.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_AUDIO_PLAYER_ERROR_UTIL_JS" file="audio_player/js/error_util.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_AUDIO_PLAYER_TEST_UTIL_JS" file="audio_player/js/test_util.js" flattenhtml="false" type="BINDATA" />
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc index b6d55980..3de0750 100644 --- a/ui/gl/gl_gl_api_implementation.cc +++ b/ui/gl/gl_gl_api_implementation.cc
@@ -4,10 +4,10 @@ #include "ui/gl/gl_gl_api_implementation.h" -#include <algorithm> #include <vector> #include "base/command_line.h" +#include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "ui/gl/gl_context.h" @@ -491,10 +491,8 @@ const char* gl_extension = reinterpret_cast<const char*>( GLApiBase::glGetStringiFn(GL_EXTENSIONS, i)); DCHECK(gl_extension != NULL); - if (std::find(disabled_exts_.begin(), disabled_exts_.end(), - gl_extension) == disabled_exts_.end()) { + if (!ContainsValue(disabled_exts_, gl_extension)) filtered_exts_.push_back(gl_extension); - } } filtered_exts_str_ = base::JoinString(filtered_exts_, " "); }
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index 9c25ff0..b69e93b 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc
@@ -4,12 +4,12 @@ #include "ui/gl/gl_surface.h" -#include <algorithm> #include <vector> #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/threading/thread_local.h" #include "base/trace_event/trace_event.h" #include "ui/gfx/swap_result.h" @@ -50,9 +50,7 @@ impl = kGLImplementationEGLGLES2; } else { impl = GetNamedGLImplementation(requested_implementation_name); - if (std::find(allowed_impls.begin(), - allowed_impls.end(), - impl) == allowed_impls.end()) { + if (!ContainsValue(allowed_impls, impl)) { LOG(ERROR) << "Requested GL implementation is not available."; return false; }
diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc index 5b7d4c0..fc93cf2b 100644 --- a/ui/message_center/message_center_impl.cc +++ b/ui/message_center/message_center_impl.cc
@@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/memory/scoped_vector.h" #include "base/observer_list.h" +#include "base/stl_util.h" #include "ui/message_center/message_center_style.h" #include "ui/message_center/message_center_switches.h" #include "ui/message_center/message_center_types.h" @@ -381,10 +382,9 @@ } void MessageCenterImpl::AddNotificationBlocker(NotificationBlocker* blocker) { - if (std::find(blockers_.begin(), blockers_.end(), blocker) != - blockers_.end()) { + if (ContainsValue(blockers_, blocker)) return; - } + blocker->AddObserver(this); blockers_.push_back(blocker); }
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index f529692..34622c4 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn
@@ -2,9 +2,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") import("//ui/ozone/ozone.gni") import("//testing/test.gni") +assert(use_ozone) + # The list of platforms that will be built. ozone_platforms = [] @@ -120,11 +123,14 @@ defines = [ "OZONE_IMPLEMENTATION" ] + public_deps = [ + ":ozone_base", + ] + deps = [ ":generate_constructor_list", ":generate_ozone_platform_list", - ":ozone_base", "//base", "//ipc", "//skia",
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc index a0900c1..8d765030 100644 --- a/ui/views/accessibility/native_view_accessibility_auralinux.cc +++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -8,6 +8,7 @@ #include <vector> #include "base/memory/singleton.h" +#include "base/stl_util.h" #include "ui/accessibility/ax_enums.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/platform/ax_platform_node_auralinux.h" @@ -44,7 +45,7 @@ return; widget = widget->GetTopLevelWidget(); - if (std::find(widgets_.begin(), widgets_.end(), widget) != widgets_.end()) + if (ContainsValue(widgets_, widget)) return; widgets_.push_back(widget);
diff --git a/ui/views/animation/button_ink_drop_delegate.cc b/ui/views/animation/button_ink_drop_delegate.cc index 5d3b9eb..2ca3ef1 100644 --- a/ui/views/animation/button_ink_drop_delegate.cc +++ b/ui/views/animation/button_ink_drop_delegate.cc
@@ -5,18 +5,18 @@ #include "ui/views/animation/button_ink_drop_delegate.h" #include "ui/events/event.h" +#include "ui/events/scoped_target_handler.h" #include "ui/views/animation/ink_drop_animation_controller.h" #include "ui/views/animation/ink_drop_animation_controller_factory.h" #include "ui/views/animation/ink_drop_host.h" #include "ui/views/animation/ink_drop_state.h" -#include "ui/views/scoped_target_handler.h" #include "ui/views/view.h" namespace views { ButtonInkDropDelegate::ButtonInkDropDelegate(InkDropHost* ink_drop_host, View* view) - : target_handler_(new views::ScopedTargetHandler(view, this)), + : target_handler_(new ui::ScopedTargetHandler(view, this)), ink_drop_host_(ink_drop_host), ink_drop_animation_controller_( InkDropAnimationControllerFactory::CreateInkDropAnimationController(
diff --git a/ui/views/animation/button_ink_drop_delegate.h b/ui/views/animation/button_ink_drop_delegate.h index 1deb51c..2e8798da 100644 --- a/ui/views/animation/button_ink_drop_delegate.h +++ b/ui/views/animation/button_ink_drop_delegate.h
@@ -11,11 +11,14 @@ #include "ui/views/animation/ink_drop_delegate.h" #include "ui/views/views_export.h" +namespace ui { +class ScopedTargetHandler; +} + namespace views { class InkDropAnimationController; class InkDropHost; -class ScopedTargetHandler; class View; // An InkDropDelegate that handles animations for toolbar buttons. @@ -37,8 +40,8 @@ void OnGestureEvent(ui::GestureEvent* event) override; private: - // An instance of ScopedTargetHandler allowing |this| to handling events. - scoped_ptr<views::ScopedTargetHandler> target_handler_; + // An instance of ScopedTargetHandler allowing |this| to handle events. + scoped_ptr<ui::ScopedTargetHandler> target_handler_; // Parent InkDropHost (typically a View) that hosts the ink ripple animations. InkDropHost* ink_drop_host_;
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index bdc906f0..b8b202b9 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -2135,6 +2135,9 @@ } void MenuController::SelectByChar(base::char16 character) { + if (!character) + return; + base::char16 char_array[] = { character, 0 }; base::char16 key = base::i18n::ToLower(char_array)[0]; MenuItemView* item = pending_state_.item;
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc index 8fd6de5..d425a6e 100644 --- a/ui/views/controls/menu/menu_controller_unittest.cc +++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -131,6 +131,10 @@ } ~TestMenuItemViewShown() override {} + void SetController(MenuController* controller) { + set_controller(controller); + } + private: DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown); }; @@ -231,6 +235,14 @@ parent, index, MenuController::INCREMENT_SELECTION_UP); } + void SelectByChar(base::char16 character) { + menu_controller_->SelectByChar(character); + } + + void SetIsCombobox(bool is_combobox) { + menu_controller_->set_is_combobox(is_combobox); + } + void RunMenu() { menu_controller_->RunMessageLoop(false); } @@ -285,6 +297,7 @@ menu_controller_->showing_ = true; menu_controller_->SetSelection( menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY); + menu_item_->SetController(menu_controller_); } scoped_ptr<Widget> owner_; @@ -484,6 +497,22 @@ ResetSelection(); } +// Tests that opening menu and calling SelectByChar works correctly. +TEST_F(MenuControllerTest, SelectByChar) { + SetIsCombobox(true); + + // Handle null character should do nothing. + SelectByChar(0); + EXPECT_EQ(0, pending_state_item()->GetCommand()); + + // Handle searching for 'f'; should find "Four". + SelectByChar('f'); + EXPECT_EQ(4, pending_state_item()->GetCommand()); + + // Clear references in menu controller to the menu item that is going away. + ResetSelection(); +} + // Tests that a menu opened asynchronously, will notify its // MenuControllerDelegate when Accept is called. TEST_F(MenuControllerTest, AsynchronousAccept) {
diff --git a/ui/views/controls/textfield/textfield_model.cc b/ui/views/controls/textfield/textfield_model.cc index d270a20..6b17c5c 100644 --- a/ui/views/controls/textfield/textfield_model.cc +++ b/ui/views/controls/textfield/textfield_model.cc
@@ -8,6 +8,8 @@ #include "base/logging.h" #include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" #include "ui/gfx/range/range.h" @@ -509,13 +511,18 @@ } bool TextfieldModel::Paste() { - base::string16 result; + base::string16 text; ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, - &result); - if (result.empty()) + &text); + if (text.empty()) return false; - InsertTextInternal(result, false); + base::string16 actual_text = base::CollapseWhitespace(text, false); + // If the clipboard contains all whitespaces then paste a single space. + if (actual_text.empty()) + actual_text = base::ASCIIToUTF16(" "); + + InsertTextInternal(actual_text, false); return true; }
diff --git a/ui/views/controls/textfield/textfield_model_unittest.cc b/ui/views/controls/textfield/textfield_model_unittest.cc index c6412098..1932f0a9 100644 --- a/ui/views/controls/textfield/textfield_model_unittest.cc +++ b/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -536,15 +536,16 @@ EXPECT_STR_EQ("HELLO ", model.text()); EXPECT_EQ(6U, model.GetCursorPosition()); - // Test that paste works regardless of the obscured bit. + // Test that paste works regardless of the obscured bit. Please note that + // trailing spaces and tabs in clipboard strings will be stripped. model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("HELLO HELLO ", model.text()); - EXPECT_EQ(12U, model.GetCursorPosition()); + EXPECT_STR_EQ("HELLO HELLO", model.text()); + EXPECT_EQ(11U, model.GetCursorPosition()); model.render_text()->SetObscured(true); EXPECT_TRUE(model.Paste()); - EXPECT_STR_EQ("HELLO HELLO HELLO ", model.text()); - EXPECT_EQ(18U, model.GetCursorPosition()); + EXPECT_STR_EQ("HELLO HELLOHELLO", model.text()); + EXPECT_EQ(16U, model.GetCursorPosition()); } static void SelectWordTestVerifier( @@ -1479,4 +1480,108 @@ // TODO(oshima): Test the behavior with an IME. } +// Tests that clipboard text with leading, trailing and interspersed tabs +// spaces etc is pasted correctly. Leading and trailing tabs should be +// stripped. Text separated by multiple tabs/spaces should be collapsed into +// one space. Text with just tabs and spaces should be pasted as one space. +TEST_F(TextfieldModelTest, Clipboard_WhiteSpaceStringTest) { + // Test 1 + // Clipboard text with a leading tab should be pasted with the tab stripped. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("\tB")); + + TextfieldModel model(NULL); + model.Append(base::ASCIIToUTF16("HELLO WORLD")); + EXPECT_STR_EQ("HELLO WORLD", model.text()); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + EXPECT_EQ(11U, model.GetCursorPosition()); + + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("HELLO WORLDB", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 2 + // Clipboard text with multiple leading tabs and spaces should be pasted with + // all tabs and spaces stripped. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("\t\t\t B")); + + model.Append(base::ASCIIToUTF16("HELLO WORLD")); + EXPECT_STR_EQ("HELLO WORLD", model.text()); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + EXPECT_EQ(11U, model.GetCursorPosition()); + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("HELLO WORLDB", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 3 + // Clipboard text with multiple tabs separating the words should be pasted + // with one space replacing all tabs. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("FOO \t\t BAR")); + + model.Append(base::ASCIIToUTF16("HELLO WORLD")); + EXPECT_STR_EQ("HELLO WORLD", model.text()); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + EXPECT_EQ(11U, model.GetCursorPosition()); + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("HELLO WORLDFOO BAR", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 4 + // Clipboard text with multiple leading tabs and multiple tabs separating + // the words should be pasted with the leading tabs stripped and one space + // replacing the intermediate tabs. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("\t\tFOO \t\t BAR")); + + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("FOO BAR", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 5 + // Clipboard text with multiple trailing tabs should be pasted with all + // trailing tabs stripped. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("FOO BAR\t\t\t")); + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("FOO BAR", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 6 + // Clipboard text with only spaces and tabs should be pasted as a single + // space. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16(" \t\t")); + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ(" ", model.text()); + + model.SelectAll(false); + model.DeleteSelection(); + EXPECT_STR_EQ("", model.text()); + + // Test 7 + // Clipboard text with lots of spaces between words should have all spaces + // replaced with a single space. + ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) + .WriteText(base::ASCIIToUTF16("FOO BAR")); + EXPECT_TRUE(model.Paste()); + EXPECT_STR_EQ("FOO BAR", model.text()); +} + } // namespace views
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn index d3b39a2..6058d93c 100644 --- a/ui/views/mus/BUILD.gn +++ b/ui/views/mus/BUILD.gn
@@ -23,9 +23,10 @@ "surface_binding.h", "surface_context_factory.cc", "surface_context_factory.h", - "window_manager_client_area_insets.h", "window_manager_connection.cc", "window_manager_connection.h", + "window_manager_frame_values.cc", + "window_manager_frame_values.h", "window_tree_host_mus.cc", "window_tree_host_mus.h", ]
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc index 042f853..2402458 100644 --- a/ui/views/mus/native_widget_mus.cc +++ b/ui/views/mus/native_widget_mus.cc
@@ -20,7 +20,7 @@ #include "ui/native_theme/native_theme_aura.h" #include "ui/views/mus/platform_window_mus.h" #include "ui/views/mus/surface_context_factory.h" -#include "ui/views/mus/window_manager_client_area_insets.h" +#include "ui/views/mus/window_manager_frame_values.h" #include "ui/views/mus/window_tree_host_mus.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/custom_frame_view.h" @@ -31,8 +31,6 @@ namespace views { namespace { -WindowManagerClientAreaInsets* window_manager_client_area_insets = nullptr; - // TODO: figure out what this should be. class FocusRulesImpl : public wm::BaseFocusRules { public: @@ -108,10 +106,9 @@ private: // Returns the default values of client area insets from the window manager. static gfx::Insets GetDefaultWindowManagerInsets(bool is_maximized) { - if (!window_manager_client_area_insets) - return gfx::Insets(); - return is_maximized ? window_manager_client_area_insets->maximized_insets - : window_manager_client_area_insets->normal_insets; + const WindowManagerFrameValues& values = + WindowManagerFrameValues::instance(); + return is_maximized ? values.maximized_insets : values.normal_insets; } // NonClientFrameView: @@ -191,15 +188,6 @@ CloseNow(); } -// static -void NativeWidgetMus::SetWindowManagerClientAreaInsets( - const WindowManagerClientAreaInsets& insets) { - delete window_manager_client_area_insets; - // This is called early on, so we don't bother trying to relayout existing - // NativeWidgetMus. When we support restarting the WM we'll need to do that. - window_manager_client_area_insets = new WindowManagerClientAreaInsets(insets); -} - void NativeWidgetMus::OnPlatformWindowClosed() { GetWidget()->Close(); } @@ -239,9 +227,15 @@ if (!Widget::RequiresNonClientView(init_params.type)) return; + ConfigurePropertiesForNewWindowFromDelegate(init_params.delegate, properties); +} + +void NativeWidgetMus::ConfigurePropertiesForNewWindowFromDelegate( + WidgetDelegate* delegate, + std::map<std::string, std::vector<uint8_t>>* properties) { (*properties)[mus::mojom::WindowManager::kResizeBehavior_Property] = mojo::TypeConverter<const std::vector<uint8_t>, int32_t>::Convert( - ResizeBehaviorFromDelegate(init_params.delegate)); + ResizeBehaviorFromDelegate(delegate)); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h index 19cb8ba..96e74c3 100644 --- a/ui/views/mus/native_widget_mus.h +++ b/ui/views/mus/native_widget_mus.h
@@ -42,6 +42,7 @@ namespace views { class SurfaceContextFactory; +class WidgetDelegate; struct WindowManagerClientAreaInsets; class WindowTreeHostMus; @@ -61,17 +62,16 @@ mus::mojom::SurfaceType surface_type); ~NativeWidgetMus() override; - // Sets the insets for the client area. These values come from the window - // manager. - static void SetWindowManagerClientAreaInsets( - const WindowManagerClientAreaInsets& insets); - // Configures the set of properties supplied to the window manager when // creating a new Window for a Widget. static void ConfigurePropertiesForNewWindow( const Widget::InitParams& init_params, std::map<std::string, std::vector<uint8_t>>* properties); + static void ConfigurePropertiesForNewWindowFromDelegate( + WidgetDelegate* widget_delegate, + std::map<std::string, std::vector<uint8_t>>* properties); + mus::Window* window() { return window_; } void OnPlatformWindowClosed();
diff --git a/ui/views/mus/window_manager_client_area_insets.h b/ui/views/mus/window_manager_client_area_insets.h deleted file mode 100644 index afc420f..0000000 --- a/ui/views/mus/window_manager_client_area_insets.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_ -#define UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_ - -#include "ui/gfx/geometry/insets.h" -#include "ui/views/mus/mus_export.h" - -namespace views { - -struct VIEWS_MUS_EXPORT WindowManagerClientAreaInsets { - gfx::Insets normal_insets; - gfx::Insets maximized_insets; -}; - -} // namespace views - -#endif // UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc index 9c8ae91..3629b94 100644 --- a/ui/views/mus/window_manager_connection.cc +++ b/ui/views/mus/window_manager_connection.cc
@@ -18,7 +18,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/mojo/init/ui_init.h" #include "ui/views/mus/native_widget_mus.h" -#include "ui/views/mus/window_manager_client_area_insets.h" +#include "ui/views/mus/window_manager_frame_values.h" #include "ui/views/views_delegate.h" namespace mojo { @@ -73,19 +73,21 @@ std::vector<gfx::Display> GetDisplaysFromWindowManager( mus::mojom::WindowManagerPtr* window_manager) { - WindowManagerClientAreaInsets client_insets; + WindowManagerFrameValues frame_values; std::vector<gfx::Display> displays; (*window_manager) ->GetConfig([&displays, - &client_insets](mus::mojom::WindowManagerConfigPtr results) { + &frame_values](mus::mojom::WindowManagerConfigPtr results) { displays = results->displays.To<std::vector<gfx::Display>>(); - client_insets.normal_insets = + frame_values.normal_insets = results->normal_client_area_insets.To<gfx::Insets>(); - client_insets.maximized_insets = + frame_values.maximized_insets = results->maximized_client_area_insets.To<gfx::Insets>(); + frame_values.max_title_bar_button_width = + results->max_title_bar_button_width; }); CHECK(window_manager->WaitForIncomingResponse()); - NativeWidgetMus::SetWindowManagerClientAreaInsets(client_insets); + WindowManagerFrameValues::SetInstance(frame_values); return displays; }
diff --git a/ui/views/mus/window_manager_frame_values.cc b/ui/views/mus/window_manager_frame_values.cc new file mode 100644 index 0000000..b4108b6 --- /dev/null +++ b/ui/views/mus/window_manager_frame_values.cc
@@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/mus/window_manager_frame_values.h" + +#include "base/lazy_instance.h" + +namespace views { +namespace { + +base::LazyInstance<WindowManagerFrameValues>::Leaky lazy_instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +WindowManagerFrameValues::WindowManagerFrameValues() + : max_title_bar_button_width(0) {} + +WindowManagerFrameValues::~WindowManagerFrameValues() {} + +// static +void WindowManagerFrameValues::SetInstance( + const WindowManagerFrameValues& values) { + lazy_instance.Get() = values; +} + +// static +const WindowManagerFrameValues& WindowManagerFrameValues::instance() { + return lazy_instance.Get(); +} + +} // namespace views
diff --git a/ui/views/mus/window_manager_frame_values.h b/ui/views/mus/window_manager_frame_values.h new file mode 100644 index 0000000..b0b8e10 --- /dev/null +++ b/ui/views/mus/window_manager_frame_values.h
@@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_FRAME_VALUES_H_ +#define UI_VIEWS_MUS_WINDOW_MANAGER_FRAME_VALUES_H_ + +#include "ui/gfx/geometry/insets.h" +#include "ui/views/mus/mus_export.h" + +namespace views { + +// Provides constants used by the window manager in rendering frame +// decorations. +struct VIEWS_MUS_EXPORT WindowManagerFrameValues { + WindowManagerFrameValues(); + ~WindowManagerFrameValues(); + + static void SetInstance(const WindowManagerFrameValues& values); + static const WindowManagerFrameValues& instance(); + + // Ideal insets the window manager renders non-client frame decorations into. + gfx::Insets normal_insets; + gfx::Insets maximized_insets; + + // Max width of buttons in the title bar. This width assumes all buttons are + // present. + int max_title_bar_button_width; +}; + +} // namespace views + +#endif // UI_VIEWS_MUS_WINDOW_MANAGER_FRAME_VALUES_H_
diff --git a/ui/views/scoped_target_handler.cc b/ui/views/scoped_target_handler.cc deleted file mode 100644 index 07ccaa8..0000000 --- a/ui/views/scoped_target_handler.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/views/scoped_target_handler.h" - -#include "ui/events/event.h" -#include "ui/events/event_handler.h" -#include "ui/events/event_target.h" -#include "ui/views/view.h" - -namespace views { - -ScopedTargetHandler::ScopedTargetHandler(View* view, - ui::EventHandler* handler) - : destroyed_flag_(NULL), view_(view), new_handler_(handler){ - original_handler_ = view_->SetTargetHandler(this); -} - -ScopedTargetHandler::~ScopedTargetHandler() { - EventHandler* handler = view_->SetTargetHandler(original_handler_); - DCHECK_EQ(this, handler); - if (destroyed_flag_) - *destroyed_flag_ = true; -} - -void ScopedTargetHandler::OnEvent(ui::Event* event) { - bool destroyed = false; - bool* old_destroyed_flag = destroyed_flag_; - destroyed_flag_ = &destroyed; - - if (original_handler_) - original_handler_->OnEvent(event); - else - EventHandler::OnEvent(event); - - if (destroyed) { - if (old_destroyed_flag) - *old_destroyed_flag = true; - return; - } - destroyed_flag_ = old_destroyed_flag; - - new_handler_->OnEvent(event); -} - -void ScopedTargetHandler::OnKeyEvent(ui::KeyEvent* event) { - static_cast<EventHandler*>(view_)->OnKeyEvent(event); -} - -void ScopedTargetHandler::OnMouseEvent(ui::MouseEvent* event) { - static_cast<EventHandler*>(view_)->OnMouseEvent(event); -} - -void ScopedTargetHandler::OnScrollEvent(ui::ScrollEvent* event) { - static_cast<EventHandler*>(view_)->OnScrollEvent(event); -} - -void ScopedTargetHandler::OnTouchEvent(ui::TouchEvent* event) { - static_cast<EventHandler*>(view_)->OnTouchEvent(event); -} - -void ScopedTargetHandler::OnGestureEvent(ui::GestureEvent* event) { - static_cast<EventHandler*>(view_)->OnGestureEvent(event); -} - -void ScopedTargetHandler::OnCancelMode(ui::CancelModeEvent* event) { - static_cast<EventHandler*>(view_)->OnCancelMode(event); -} - -} // namespace views
diff --git a/ui/views/scoped_target_handler.h b/ui/views/scoped_target_handler.h deleted file mode 100644 index 75b4f90a..0000000 --- a/ui/views/scoped_target_handler.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_VIEWS_SCOPED_TARGET_HANDLER_H_ -#define UI_VIEWS_SCOPED_TARGET_HANDLER_H_ - -#include "base/macros.h" -#include "ui/events/event_handler.h" -#include "ui/views/views_export.h" - -namespace views { - -class View; - -// An EventHandler that replaces an View's target handler with itself to pass -// events first to the original handlers and second to an additional new -// EventHandler. The new handler gets called after the original handlers even -// if they call SetHandled() or StopPropagation() on the event. -class VIEWS_EXPORT ScopedTargetHandler : public ui::EventHandler { - public: - ScopedTargetHandler(View* view, ui::EventHandler* new_handler); - ~ScopedTargetHandler() override; - - // ui::EventHandler: - void OnEvent(ui::Event* event) override; - void OnKeyEvent(ui::KeyEvent* event) override; - void OnMouseEvent(ui::MouseEvent* event) override; - void OnScrollEvent(ui::ScrollEvent* event) override; - void OnTouchEvent(ui::TouchEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnCancelMode(ui::CancelModeEvent* event) override; - - private: - // If non-null the destructor sets this to true. This is set while handling - // an event and used to detect if |this| has been deleted. - bool* destroyed_flag_; - - // An View that has its target handler replaced with |this| for a life time of - // |this|. - View* view_; - - // An EventHandler that gets restored on |view_| when |this| is destroyed. - ui::EventHandler* original_handler_; - - // A new handler that gets events in addition to the |original_handler_| or - // |view_|. - ui::EventHandler* new_handler_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTargetHandler); -}; - -} // namespace views - -#endif // UI_VIEWS_SCOPED_TARGET_HANDLER_H_
diff --git a/ui/views/scoped_target_handler_unittest.cc b/ui/views/scoped_target_handler_unittest.cc deleted file mode 100644 index 42bdc5bb..0000000 --- a/ui/views/scoped_target_handler_unittest.cc +++ /dev/null
@@ -1,187 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/views/scoped_target_handler.h" - -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/events/event_handler.h" -#include "ui/events/event_utils.h" -#include "ui/views/view.h" - -namespace views { - -namespace { - -// A View that holds ownership of its target and delegate EventHandlers. -class TestView : public View { - public: - TestView() {} - ~TestView() override {} - - void SetHandler(scoped_ptr<ui::EventHandler> target_handler, - scoped_ptr<ui::EventHandler> delegate) { - target_handler_ = target_handler.Pass(); - delegate_ = delegate.Pass(); - } - - void DispatchEvent(ui::Event* event) { target_handler()->OnEvent(event); } - - private: - scoped_ptr<ui::EventHandler> target_handler_; - scoped_ptr<ui::EventHandler> delegate_; - - DISALLOW_COPY_AND_ASSIGN(TestView); -}; - -// An EventHandler that sets itself as a target handler for a View and can -// recursively dispatch an Event. -class NestedEventHandler : public ui::EventHandler { - public: - NestedEventHandler(TestView* view, int nesting) - : view_(view), nesting_(nesting) { - original_handler_ = view_->SetTargetHandler(this); - } - ~NestedEventHandler() override { - ui::EventHandler* handler = view_->SetTargetHandler(original_handler_); - DCHECK_EQ(this, handler); - } - - protected: - void OnEvent(ui::Event* event) override { - if (--nesting_ == 0) - return; - view_->DispatchEvent(event); - } - - private: - TestView* view_; - int nesting_; - ui::EventHandler* original_handler_; - - DISALLOW_COPY_AND_ASSIGN(NestedEventHandler); -}; - -// An EventHandler that sets itself as a target handler for a View and destroys -// that View when handling an Event, possibly after recursively handling the -// Event. -class ViewDestroyingEventHandler : public ui::EventHandler { - public: - ViewDestroyingEventHandler(TestView* view, int nesting) - : view_(view), nesting_(nesting) { - original_handler_ = view_->SetTargetHandler(this); - } - ~ViewDestroyingEventHandler() override { - ui::EventHandler* handler = view_->SetTargetHandler(original_handler_); - DCHECK_EQ(this, handler); - } - - protected: - void OnEvent(ui::Event* event) override { - if (--nesting_ == 0) { - delete view_; - return; - } - view_->DispatchEvent(event); - } - - private: - TestView* view_; - int nesting_; - ui::EventHandler* original_handler_; - - DISALLOW_COPY_AND_ASSIGN(ViewDestroyingEventHandler); -}; - -// An EventHandler that can be set to receive events in addition to the target -// handler and counts the Events that it receives. -class EventCountingEventHandler : public ui::EventHandler { - public: - EventCountingEventHandler(View* view, int* count) - : scoped_target_handler_(new views::ScopedTargetHandler(view, this)), - count_(count) {} - ~EventCountingEventHandler() override {} - - protected: - void OnEvent(ui::Event* event) override { (*count_)++; } - - private: - scoped_ptr<ScopedTargetHandler> scoped_target_handler_; - int* count_; - - DISALLOW_COPY_AND_ASSIGN(EventCountingEventHandler); -}; - -} // namespace - -// Tests that a ScopedTargetHandler invokes both the target and a delegate. -TEST(ScopedTargetHandlerTest, HandlerInvoked) { - int count = 0; - TestView* view = new TestView; - scoped_ptr<NestedEventHandler> target_handler( - new NestedEventHandler(view, 1)); - scoped_ptr<EventCountingEventHandler> delegate( - new EventCountingEventHandler(view, &count)); - view->SetHandler(target_handler.Pass(), delegate.Pass()); - ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - view->DispatchEvent(&event); - EXPECT_EQ(1, count); - delete view; -} - -// Tests that a ScopedTargetHandler invokes both the target and a delegate when -// an Event is dispatched recursively such as with synthetic events. -TEST(ScopedTargetHandlerTest, HandlerInvokedNested) { - int count = 0; - TestView* view = new TestView; - scoped_ptr<NestedEventHandler> target_handler( - new NestedEventHandler(view, 2)); - scoped_ptr<EventCountingEventHandler> delegate( - new EventCountingEventHandler(view, &count)); - view->SetHandler(target_handler.Pass(), delegate.Pass()); - ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - view->DispatchEvent(&event); - EXPECT_EQ(2, count); - delete view; -} - -// Tests that a it is safe to delete a ScopedTargetHandler while handling an -// event. -TEST(ScopedTargetHandlerTest, SafeToDestroy) { - int count = 0; - TestView* view = new TestView; - scoped_ptr<ViewDestroyingEventHandler> target_handler( - new ViewDestroyingEventHandler(view, 1)); - scoped_ptr<EventCountingEventHandler> delegate( - new EventCountingEventHandler(view, &count)); - view->SetHandler(target_handler.Pass(), delegate.Pass()); - ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - view->DispatchEvent(&event); - EXPECT_EQ(0, count); -} - -// Tests that a it is safe to delete a ScopedTargetHandler while handling an -// event recursively. -TEST(ScopedTargetHandlerTest, SafeToDestroyNested) { - int count = 0; - TestView* view = new TestView; - scoped_ptr<ViewDestroyingEventHandler> target_handler( - new ViewDestroyingEventHandler(view, 2)); - scoped_ptr<EventCountingEventHandler> delegate( - new EventCountingEventHandler(view, &count)); - view->SetHandler(target_handler.Pass(), delegate.Pass()); - ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - view->DispatchEvent(&event); - EXPECT_EQ(0, count); -} - -} // namespace views
diff --git a/ui/views/view.cc b/ui/views/view.cc index c816e2d..4aa6d5a 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" @@ -1098,10 +1099,9 @@ if (!accelerators_.get()) accelerators_.reset(new std::vector<ui::Accelerator>()); - if (std::find(accelerators_->begin(), accelerators_->end(), accelerator) == - accelerators_->end()) { + if (!ContainsValue(*accelerators_.get(), accelerator)) accelerators_->push_back(accelerator); - } + RegisterPendingAccelerators(); }
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 163a9f7..503eead 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc
@@ -23,6 +23,7 @@ #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/scoped_target_handler.h" #include "ui/gfx/canvas.h" #include "ui/gfx/path.h" #include "ui/gfx/transform.h" @@ -32,7 +33,6 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/focus/view_storage.h" -#include "ui/views/scoped_target_handler.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" #include "ui/views/widget/native_widget.h" @@ -4327,7 +4327,7 @@ v->Reset(); { TestEventHandler handler(v); - ScopedTargetHandler scoped_target_handler(v, &handler); + ui::ScopedTargetHandler scoped_target_handler(v, &handler); // View's target EventHandler should be set to the |scoped_target_handler|. EXPECT_EQ(&scoped_target_handler, v->SetTargetHandler(&scoped_target_handler));
diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 05bc7ad..328999b 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp
@@ -272,8 +272,6 @@ 'repeat_controller.h', 'round_rect_painter.cc', 'round_rect_painter.h', - 'scoped_target_handler.cc', - 'scoped_target_handler.h', 'shadow_border.cc', 'shadow_border.h', 'style/mac/dialog_button_border_mac.cc', @@ -590,7 +588,6 @@ 'layout/grid_layout_unittest.cc', 'rect_based_targeting_utils_unittest.cc', 'run_all_unittests.cc', - 'scoped_target_handler_unittest.cc', 'style/mac/dialog_button_border_mac_unittest.cc', 'view_model_unittest.cc', 'view_model_utils_unittest.cc',
diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc index 129cfda..9ef09cd 100644 --- a/ui/wm/core/window_animations.cc +++ b/ui/wm/core/window_animations.cc
@@ -95,11 +95,8 @@ DCHECK(iter != window_->parent()->children().end()); aura::Window* topmost_transient_child = NULL; for (++iter; iter != window_->parent()->children().end(); ++iter) { - if (std::find(transient_children.begin(), - transient_children.end(), - *iter) != transient_children.end()) { + if (ContainsValue(transient_children, *iter)) topmost_transient_child = *iter; - } } if (topmost_transient_child) { window_->parent()->layer()->StackAbove(