diff --git a/DEPS b/DEPS index 4bfd39b6..b97b3e4 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': 'e9573317d35d08254412eb407211f3607f8f74fb', + 'skia_revision': 'eae84c2e0e2126374cd488a1c8a3e18169145635', # 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': 'e78b4e2e8eef9db0bd74d2dc2d8b0927e1004cdf', + 'v8_revision': '2801e08d8f527caaa58b07607ac0fbc04aa998f7', # 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. @@ -184,7 +184,7 @@ Var('chromium_git') + '/webm/libvpx.git' + '@' + 'c0307e6cea0fcd79577eaa107f76b07acaf1d4e6', 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '2dc5618f9b6f04d4ba4cda56350051c815841e34', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '2ab535183e2fca15d37be86bf0edf5aa8c6767cf', 'src/third_party/libjingle/source/talk': Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'b62ca7e76805b8d87795c73fcdd5dd1457c14461', # commit position 11358 @@ -271,7 +271,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - 'f7563a0c32bf3a59ff49150461bafbfe0082f17b', + '4028a4f07d37b511af1052485fe9097b9e4cabdf', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/base/BUILD.gn b/base/BUILD.gn index 5e94b37..3f8380c7 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -849,11 +849,8 @@ "trace_event/process_memory_dump.h", "trace_event/process_memory_maps.cc", "trace_event/process_memory_maps.h", - "trace_event/process_memory_maps_dump_provider.h", "trace_event/process_memory_totals.cc", "trace_event/process_memory_totals.h", - "trace_event/process_memory_totals_dump_provider.cc", - "trace_event/process_memory_totals_dump_provider.h", "trace_event/trace_buffer.cc", "trace_event/trace_buffer.h", "trace_event/trace_config.cc", @@ -994,7 +991,6 @@ "sys_info_linux.cc", "trace_event/malloc_dump_provider.cc", "trace_event/malloc_dump_provider.h", - "trace_event/process_memory_maps_dump_provider.cc", ] set_sources_assignment_filter(sources_assignment_filter) @@ -1061,7 +1057,6 @@ "sync_socket_posix.cc", "sys_info.cc", "sys_info_posix.cc", - "trace_event/process_memory_totals_dump_provider.cc", "trace_event/trace_event_system_stats_monitor.cc", ] @@ -1190,7 +1185,6 @@ sources += [ "trace_event/malloc_dump_provider.cc", "trace_event/malloc_dump_provider.h", - "trace_event/process_memory_maps_dump_provider.cc", ] if (is_asan || is_lsan || is_msan || is_tsan) { @@ -1828,7 +1822,6 @@ "trace_event/memory_allocator_dump_unittest.cc", "trace_event/memory_dump_manager_unittest.cc", "trace_event/process_memory_dump_unittest.cc", - "trace_event/process_memory_totals_dump_provider_unittest.cc", "trace_event/trace_config_memory_test_util.h", "trace_event/trace_config_unittest.cc", "trace_event/trace_event_argument_unittest.cc", @@ -1945,10 +1938,6 @@ } } - if (is_linux || is_android) { - sources += [ "trace_event/process_memory_maps_dump_provider_unittest.cc" ] - } - if (!is_linux || use_ozone) { sources -= [ "message_loop/message_pump_glib_unittest.cc" ] }
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc index bcebcf5..7a731bb 100644 --- a/base/process/process_metrics_linux.cc +++ b/base/process/process_metrics_linux.cc
@@ -86,7 +86,8 @@ return value; } } - NOTREACHED(); + // This can be reached if the process dies when proc is read -- in that case, + // the kernel can return missing fields. return 0; }
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index 156f3247..a0f0af37 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -23,14 +23,6 @@ #include "base/trace_event/trace_event_argument.h" #include "build/build_config.h" -#if !defined(OS_NACL) -#include "base/trace_event/process_memory_totals_dump_provider.h" -#endif - -#if defined(OS_LINUX) || defined(OS_ANDROID) -#include "base/trace_event/process_memory_maps_dump_provider.h" -#endif - #if defined(OS_ANDROID) #include "base/trace_event/java_heap_dump_provider_android.h" #endif @@ -166,20 +158,10 @@ } // Enable the core dump providers. -#if !defined(OS_NACL) - RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance(), - "ProcessMemoryTotals", nullptr); -#endif - #if defined(MALLOC_MEMORY_TRACING_SUPPORTED) RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr); #endif -#if defined(OS_LINUX) || defined(OS_ANDROID) - RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance(), - "ProcessMemoryMaps", nullptr); -#endif - #if defined(OS_ANDROID) RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap", nullptr);
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc deleted file mode 100644 index 4c3959f..0000000 --- a/base/trace_event/process_memory_maps_dump_provider.cc +++ /dev/null
@@ -1,176 +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 "base/trace_event/process_memory_maps_dump_provider.h" - -#include <stdint.h> - -#include "base/files/scoped_file.h" -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/process_memory_maps.h" - -namespace base { -namespace trace_event { - -// static -FILE* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr; - -namespace { - -const uint32_t kMaxLineSize = 4096; - -bool ParseSmapsHeader(const char* header_line, - ProcessMemoryMaps::VMRegion* region) { - // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n" - bool res = true; // Whether this region should be appended or skipped. - uint64_t end_addr = 0; - char protection_flags[5] = {0}; - char mapped_file[kMaxLineSize]; - - if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n", - ®ion->start_address, &end_addr, protection_flags, - mapped_file) != 4) - return false; - - if (end_addr > region->start_address) { - region->size_in_bytes = end_addr - region->start_address; - } else { - // This is not just paranoia, it can actually happen (See crbug.com/461237). - region->size_in_bytes = 0; - res = false; - } - - region->protection_flags = 0; - if (protection_flags[0] == 'r') { - region->protection_flags |= - ProcessMemoryMaps::VMRegion::kProtectionFlagsRead; - } - if (protection_flags[1] == 'w') { - region->protection_flags |= - ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite; - } - if (protection_flags[2] == 'x') { - region->protection_flags |= - ProcessMemoryMaps::VMRegion::kProtectionFlagsExec; - } - - region->mapped_file = mapped_file; - TrimWhitespaceASCII(region->mapped_file, TRIM_ALL, ®ion->mapped_file); - - return res; -} - -uint64_t ReadCounterBytes(char* counter_line) { - uint64_t counter_value = 0; - int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value); - DCHECK_EQ(1, res); - return counter_value * 1024; -} - -uint32_t ParseSmapsCounter(char* counter_line, - ProcessMemoryMaps::VMRegion* region) { - // A smaps counter lines looks as follows: "RSS: 0 Kb\n" - uint32_t res = 1; - char counter_name[20]; - int did_read = sscanf(counter_line, "%19[^\n ]", counter_name); - DCHECK_EQ(1, did_read); - - if (strcmp(counter_name, "Pss:") == 0) { - region->byte_stats_proportional_resident = ReadCounterBytes(counter_line); - } else if (strcmp(counter_name, "Private_Dirty:") == 0) { - region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line); - } else if (strcmp(counter_name, "Private_Clean:") == 0) { - region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line); - } else if (strcmp(counter_name, "Shared_Dirty:") == 0) { - region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line); - } else if (strcmp(counter_name, "Shared_Clean:") == 0) { - region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line); - } else if (strcmp(counter_name, "Swap:") == 0) { - region->byte_stats_swapped = ReadCounterBytes(counter_line); - } else { - res = 0; - } - - return res; -} - -uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file, ProcessMemoryMaps* pmm) { - if (!smaps_file) - return 0; - - fseek(smaps_file, 0, SEEK_SET); - - char line[kMaxLineSize]; - const uint32_t kNumExpectedCountersPerRegion = 6; - uint32_t counters_parsed_for_current_region = 0; - uint32_t num_valid_regions = 0; - ProcessMemoryMaps::VMRegion region; - bool should_add_current_region = false; - for (;;) { - line[0] = '\0'; - if (fgets(line, kMaxLineSize, smaps_file) == nullptr) - break; - DCHECK_GT(strlen(line), 0u); - if (isxdigit(line[0]) && !isupper(line[0])) { - region = ProcessMemoryMaps::VMRegion(); - counters_parsed_for_current_region = 0; - should_add_current_region = ParseSmapsHeader(line, ®ion); - } else { - counters_parsed_for_current_region += ParseSmapsCounter(line, ®ion); - DCHECK_LE(counters_parsed_for_current_region, - kNumExpectedCountersPerRegion); - if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) { - if (should_add_current_region) { - pmm->AddVMRegion(region); - ++num_valid_regions; - should_add_current_region = false; - } - } - } - } - return num_valid_regions; -} - -} // namespace - -// static -ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() { - return Singleton<ProcessMemoryMapsDumpProvider, - LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get(); -} - -ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() { -} - -ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() { -} - -// Called at trace dump point time. Creates a snapshot of the memory maps for -// the current process. -bool ProcessMemoryMapsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) { - // Snapshot of memory maps is not taken for light dump requests. - if (args.level_of_detail == MemoryDumpLevelOfDetail::LIGHT) - return true; - - uint32_t res = 0; - if (UNLIKELY(proc_smaps_for_testing)) { - res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps()); - } else { - ScopedFILE smaps_file(fopen("/proc/self/smaps", "r")); - res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps()); - } - - if (res > 0) { - pmd->set_has_process_mmaps(); - return true; - } - return false; -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h deleted file mode 100644 index 84badfe..0000000 --- a/base/trace_event/process_memory_maps_dump_provider.h +++ /dev/null
@@ -1,43 +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 BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_ -#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_ - -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "base/trace_event/memory_dump_provider.h" -#include "build/build_config.h" - -namespace base { -namespace trace_event { - -// Dump provider which collects process-wide memory stats. -class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider { - public: - static ProcessMemoryMapsDumpProvider* GetInstance(); - - // MemoryDumpProvider implementation. - bool OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) override; - - private: - friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>; - FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps); - -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL) - static FILE* proc_smaps_for_testing; -#endif - - ProcessMemoryMapsDumpProvider(); - ~ProcessMemoryMapsDumpProvider() override; - - DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider); -}; - -} // namespace trace_event -} // namespace base - -#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc deleted file mode 100644 index 1713ebf0..0000000 --- a/base/trace_event/process_memory_totals_dump_provider.cc +++ /dev/null
@@ -1,92 +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 "base/trace_event/process_memory_totals_dump_provider.h" - -#include <stddef.h> - -#include "base/process/process_metrics.h" -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/process_memory_totals.h" -#include "build/build_config.h" - -#if defined(OS_LINUX) || defined(OS_ANDROID) -#include <fcntl.h> - -#include "base/files/file_util.h" - -namespace { -bool kernel_supports_rss_peak_reset = true; -const char kClearPeakRssCommand[] = "5"; -} -#endif - -namespace base { -namespace trace_event { - -// static -uint64_t ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0; - -// static -ProcessMemoryTotalsDumpProvider* -ProcessMemoryTotalsDumpProvider::GetInstance() { - return Singleton< - ProcessMemoryTotalsDumpProvider, - LeakySingletonTraits<ProcessMemoryTotalsDumpProvider>>::get(); -} - -ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider() - : process_metrics_(ProcessMetrics::CreateCurrentProcessMetrics()) {} - -ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() { -} - -// Called at trace dump point time. Creates a snapshot the memory counters for -// the current process. -bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) { - const uint64_t rss_bytes = rss_bytes_for_testing - ? rss_bytes_for_testing - : process_metrics_->GetWorkingSetSize(); - - uint64_t peak_rss_bytes = 0; - -#if !defined(OS_IOS) - peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize(); -#if defined(OS_LINUX) || defined(OS_ANDROID) - if (kernel_supports_rss_peak_reset) { - // TODO(ssid): Fix crbug.com/461788 to write to the file from sandboxed - // processes. - int clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY); - if (clear_refs_fd > 0 && - WriteFileDescriptor(clear_refs_fd, kClearPeakRssCommand, - sizeof(kClearPeakRssCommand))) { - pmd->process_totals()->set_is_peak_rss_resetable(true); - } else { - kernel_supports_rss_peak_reset = false; - } - close(clear_refs_fd); - } -#elif defined(OS_MACOSX) - size_t private_bytes; - bool res = process_metrics_->GetMemoryBytes(&private_bytes, - nullptr /* shared_bytes */); - if (res) { - pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes); - } -#endif // defined(OS_LINUX) || defined(OS_ANDROID) -#endif // !defined(OS_IOS) - - if (rss_bytes > 0) { - pmd->process_totals()->set_resident_set_bytes(rss_bytes); - pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes); - pmd->set_has_process_totals(); - return true; - } - - return false; -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h deleted file mode 100644 index d9573d31..0000000 --- a/base/trace_event/process_memory_totals_dump_provider.h +++ /dev/null
@@ -1,48 +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 BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_ -#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_ - -#include <stdint.h> - -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/trace_event/memory_dump_provider.h" - -namespace base { - -class ProcessMetrics; - -namespace trace_event { - -// Dump provider which collects process-wide memory stats. -class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider { - public: - static ProcessMemoryTotalsDumpProvider* GetInstance(); - - // MemoryDumpProvider implementation. - bool OnMemoryDump(const MemoryDumpArgs& args, - ProcessMemoryDump* pmd) override; - - private: - friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>; - FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS); - - static uint64_t rss_bytes_for_testing; - - ProcessMemoryTotalsDumpProvider(); - ~ProcessMemoryTotalsDumpProvider() override; - - scoped_ptr<ProcessMetrics> process_metrics_; - - DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotalsDumpProvider); -}; - -} // namespace trace_event -} // namespace base - -#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc deleted file mode 100644 index d3f517e2..0000000 --- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc +++ /dev/null
@@ -1,48 +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 "base/trace_event/process_memory_totals_dump_provider.h" - -#include <stddef.h> -#include <stdint.h> - -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/process_memory_totals.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace trace_event { - -TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) { - const MemoryDumpArgs high_detail_args = {MemoryDumpLevelOfDetail::DETAILED}; - auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance(); - scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr)); - scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr)); - - ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024; - pmtdp->OnMemoryDump(high_detail_args, pmd_before.get()); - - // Pretend that the RSS of the process increased of +1M. - const size_t kAllocSize = 1048576; - ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize; - - pmtdp->OnMemoryDump(high_detail_args, pmd_after.get()); - - ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0; - - ASSERT_TRUE(pmd_before->has_process_totals()); - ASSERT_TRUE(pmd_after->has_process_totals()); - - const uint64_t rss_before = - pmd_before->process_totals()->resident_set_bytes(); - const uint64_t rss_after = pmd_after->process_totals()->resident_set_bytes(); - - EXPECT_NE(0U, rss_before); - EXPECT_NE(0U, rss_after); - - EXPECT_EQ(rss_after - rss_before, kAllocSize); -} - -} // namespace trace_event -} // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi index 6948d7c..090f7da2c 100644 --- a/base/trace_event/trace_event.gypi +++ b/base/trace_event/trace_event.gypi
@@ -36,11 +36,8 @@ 'trace_event/process_memory_dump.h', 'trace_event/process_memory_maps.cc', 'trace_event/process_memory_maps.h', - 'trace_event/process_memory_maps_dump_provider.h', 'trace_event/process_memory_totals.cc', 'trace_event/process_memory_totals.h', - 'trace_event/process_memory_totals_dump_provider.cc', - 'trace_event/process_memory_totals_dump_provider.h', 'trace_event/trace_buffer.cc', 'trace_event/trace_buffer.h', 'trace_event/trace_config.cc', @@ -79,7 +76,6 @@ 'trace_event/memory_allocator_dump_unittest.cc', 'trace_event/memory_dump_manager_unittest.cc', 'trace_event/process_memory_dump_unittest.cc', - 'trace_event/process_memory_totals_dump_provider_unittest.cc', 'trace_event/trace_config_memory_test_util.h', 'trace_event/trace_config_unittest.cc', 'trace_event/trace_event_argument_unittest.cc', @@ -95,14 +91,6 @@ 'trace_event/malloc_dump_provider.h', ], }], - ['OS == "linux" or OS == "android"', { - 'trace_event_sources': [ - 'trace_event/process_memory_maps_dump_provider.cc', - ], - 'trace_event_test_sources' : [ - 'trace_event/process_memory_maps_dump_provider_unittest.cc', - ], - }], ['OS == "android"', { 'trace_event_test_sources' : [ 'trace_event/trace_event_android_unittest.cc',
diff --git a/breakpad/breakpad.gyp b/breakpad/breakpad.gyp index 69ce5be..7053d89 100644 --- a/breakpad/breakpad.gyp +++ b/breakpad/breakpad.gyp
@@ -311,6 +311,7 @@ 'xcode_settings' : { 'WARNING_CFLAGS': [ # See https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675. + # TODO(crbug.com/569158): remove when fixed. '-Wno-deprecated-declarations', ], }, @@ -871,6 +872,13 @@ 'src', ], }, + 'xcode_settings' : { + 'WARNING_CFLAGS': [ + # See https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675. + # TODO(crbug.com/569158): remove when fixed. + '-Wno-deprecated-declarations', + ], + }, } ] }],
diff --git a/build/android/devil/utils/lsusb_test.py b/build/android/devil/utils/lsusb_test.py index 7c80d6e..529a4b0 100755 --- a/build/android/devil/utils/lsusb_test.py +++ b/build/android/devil/utils/lsusb_test.py
@@ -222,25 +222,25 @@ def testLsusb(self): with self.assertCalls( (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb'], timeout=2), (None, DEVICE_LIST)), + ['lsusb'], timeout=10), (None, DEVICE_LIST)), (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb', '-v', '-s', '003:007'], timeout=2), (None, RAW_OUTPUT))): + ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))): self.assertDictEqual(lsusb.lsusb().pop(), EXPECTED_RESULT) def testGetSerial(self): with self.assertCalls( (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb'], timeout=2), (None, DEVICE_LIST)), + ['lsusb'], timeout=10), (None, DEVICE_LIST)), (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb', '-v', '-s', '003:007'], timeout=2), (None, RAW_OUTPUT))): + ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))): self.assertEqual(lsusb.get_android_devices(), ['01d2450ea194a93b']) def testGetLsusbSerial(self): with self.assertCalls( (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb'], timeout=2), (None, DEVICE_LIST)), + ['lsusb'], timeout=10), (None, DEVICE_LIST)), (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout( - ['lsusb', '-v', '-s', '003:007'], timeout=2), (None, RAW_OUTPUT))): + ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))): out = lsusb.lsusb().pop() self.assertEqual(lsusb.get_lsusb_serial(out), '01d2450ea194a93b')
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java index c0823d3..466b802 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
@@ -144,6 +144,8 @@ nativeOnCastStopping(mNativeRemoteMediaPlayerBridge); } mActive = false; + // Free the poster bitmap to save memory + mPosterBitmap = null; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java index e8236b1..5593a0f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
@@ -272,7 +272,7 @@ @CalledByNative public void closeRoute(String routeId) { MediaRouteProvider provider = mRouteIdsToProviders.get(routeId); - assert provider != null; + if (provider == null) return; provider.closeRoute(routeId); } @@ -284,7 +284,7 @@ @CalledByNative public void detachRoute(String routeId) { MediaRouteProvider provider = mRouteIdsToProviders.get(routeId); - assert provider != null; + if (provider == null) return; provider.detachRoute(routeId); mRouteIdsToProviders.remove(routeId); @@ -299,7 +299,10 @@ @CalledByNative public void sendStringMessage(String routeId, String message, int callbackId) { MediaRouteProvider provider = mRouteIdsToProviders.get(routeId); - assert provider != null; + if (provider == null) { + nativeOnMessageSentResult(mNativeMediaRouterAndroid, false, callbackId); + return; + } provider.sendStringMessage(routeId, message, callbackId); } @@ -313,7 +316,10 @@ @CalledByNative public void sendBinaryMessage(String routeId, byte[] data, int callbackId) { MediaRouteProvider provider = mRouteIdsToProviders.get(routeId); - assert provider != null; + if (provider == null) { + nativeOnMessageSentResult(mNativeMediaRouterAndroid, false, callbackId); + return; + } provider.sendBinaryMessage(routeId, data, callbackId); }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index f588683a..6a564f3 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -62,6 +62,7 @@ "//components/certificate_reporting:encrypted_cert_logger_proto", "//components/drive", "//components/drive:drive_chromeos", + "//components/feedback", "//components/flags_ui", "//components/login", "//components/onc",
diff --git a/chrome/browser/chromeos/policy/DEPS b/chrome/browser/chromeos/policy/DEPS index 887ac0fd..a4f1c9827 100644 --- a/chrome/browser/chromeos/policy/DEPS +++ b/chrome/browser/chromeos/policy/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+components/feedback", "+components/invalidation", "+components/user_manager", ]
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc index bb68674..8664c53 100644 --- a/chrome/browser/chromeos/policy/system_log_uploader.cc +++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/policy/system_log_uploader.h" +#include "system_log_uploader.h" #include <utility> @@ -10,11 +10,7 @@ #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/file_util.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" #include "base/strings/stringprintf.h" #include "base/task_runner_util.h" #include "chrome/browser/browser_process.h" @@ -22,11 +18,10 @@ #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h" #include "chrome/common/chrome_switches.h" +#include "components/feedback/anonymizer_tool.h" #include "components/policy/core/browser/browser_policy_connector.h" -#include "components/policy/core/common/cloud/enterprise_metrics.h" #include "content/public/browser/browser_thread.h" #include "net/http/http_request_headers.h" -#include "third_party/re2/src/re2/re2.h" namespace { // The maximum number of successive retries. @@ -44,39 +39,12 @@ "/var/log/net.log", "/var/log/net.1.log", "/var/log/ui/ui.LATEST", "/var/log/update_engine.log"}; -const char kEmailAddress[] = - "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}\\@" - "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+"; -const char kIPAddress[] = - "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])" - "\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2" - "[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" - "[0-9]{2}|[1-9][0-9]|[0-9]))"; -const char kIPv6Address[] = - "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" - "([0-9a-fA-F]{1,4}:){1,7}:|" - "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" - "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" - "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" - "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" - "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" - "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" - ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" - "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" - "::(ffff(:0{1,4}){0,1}:){0,1}" - "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" - "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" - "([0-9a-fA-F]{1,4}:){1,4}:" - "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" - "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"; - -const char kWebUrl[] = "(http|https|Http|Https|rtsp|Rtsp):\\/\\/"; - -// Reads the system log files as binary files, stores the files as pairs -// (file name, data) and returns. Called on blocking thread. +// Reads the system log files as binary files, anonymizes data, stores the files +// as pairs (file name, data) and returns. Called on blocking thread. scoped_ptr<policy::SystemLogUploader::SystemLogs> ReadFiles() { scoped_ptr<policy::SystemLogUploader::SystemLogs> system_logs( new policy::SystemLogUploader::SystemLogs()); + feedback::AnonymizerTool anonymizer; for (auto const file_path : kSystemLogFileNames) { if (!base::PathExists(base::FilePath(file_path))) continue; @@ -86,7 +54,8 @@ << file_path << std::endl; } system_logs->push_back(std::make_pair( - file_path, policy::SystemLogUploader::RemoveSensitiveData(data))); + file_path, + policy::SystemLogUploader::RemoveSensitiveData(&anonymizer, data))); } return system_logs; } @@ -155,11 +124,6 @@ return upload_frequency; } -void RecordSystemLogPIILeak(policy::SystemLogPIIType type) { - UMA_HISTOGRAM_ENUMERATION(policy::kMetricSystemLogPII, type, - policy::SYSTEM_LOG_PII_TYPE_SIZE); -} - std::string GetUploadUrl() { return policy::BrowserPolicyConnector::GetDeviceManagementUrl() + kSystemLogUploadUrlTail; @@ -248,48 +212,11 @@ } // static -std::string SystemLogUploader::RemoveSensitiveData(const std::string& data) { - std::string result = ""; - RE2 email_pattern(kEmailAddress), ipv4_pattern(kIPAddress), - ipv6_pattern(kIPv6Address), url_pattern(kWebUrl); - - for (const std::string& line : base::SplitString( - data, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) { - // Email. - if (RE2::PartialMatch(line, email_pattern)) { - RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_EMAIL_ADDRESS); - continue; - } - - // IPv4 address. - if (RE2::PartialMatch(line, ipv4_pattern)) { - RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_IP_ADDRESS); - continue; - } - - // IPv6 address. - if (RE2::PartialMatch(line, ipv6_pattern)) { - RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_IP_ADDRESS); - continue; - } - - // URL. - if (RE2::PartialMatch(line, url_pattern)) { - RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_WEB_URL); - continue; - } - - // SSID. - if (line.find("SSID=") != std::string::npos) { - RecordSystemLogPIILeak(SYSTEM_LOG_PII_TYPE_SSID); - continue; - } - - result += line + "\n"; - } - return result; +std::string SystemLogUploader::RemoveSensitiveData( + feedback::AnonymizerTool* const anonymizer, + const std::string& data) { + return anonymizer->Anonymize(data); } - void SystemLogUploader::RefreshUploadSettings() { // Attempt to fetch the current value of the reporting settings. // If trusted values are not available, register this function to be called
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.h b/chrome/browser/chromeos/policy/system_log_uploader.h index 5a3d624..2da5365 100644 --- a/chrome/browser/chromeos/policy/system_log_uploader.h +++ b/chrome/browser/chromeos/policy/system_log_uploader.h
@@ -21,6 +21,10 @@ class SequencedTaskRunner; } +namespace feedback { +class AnonymizerTool; +} + namespace policy { // Class responsible for periodically uploading system logs, it handles the @@ -78,9 +82,11 @@ void OnSuccess() override; void OnFailure(UploadJob::ErrorCode error_code) override; - // Remove lines from |data| that contain common PII (IP addresses, SSIDs, URLs - // e-mail addresses). - static std::string RemoveSensitiveData(const std::string& data); + // Remove lines from |data| that contain common PII (IP addresses, BSSIDs, + // SSIDs, URLs, e-mail addresses). + static std::string RemoveSensitiveData( + feedback::AnonymizerTool* const anonymizer, + const std::string& data); private: // Updates the system log upload enabled field from settings.
diff --git a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc index e30311c..d5bbe14 100644 --- a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc +++ b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/time/time.h" #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" +#include "components/feedback/anonymizer_tool.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "net/http/http_request_headers.h" @@ -288,23 +289,31 @@ // Test RemovePII function. TEST_F(SystemLogUploaderTest, TestPII) { + feedback::AnonymizerTool anonymizer; std::string data = - "aaaaaaaaSSID=123aaaaaaaaaaa\n" // SSID. + "aaaaaaaa [SSID=123aaaaaa]aaaaa\n" // SSID. "aaaaaaaahttp://tets.comaaaaaaa\n" // URL. "aaaaaemail@example.comaaa\n" // Email address. - "example@@1234\n" // No PII, it is not valid email address. - "255.255.355.255\n" // No PII, it is not valid IP address format. - "aaaa123.123.45.4aaa\n" // IP address. - "11:11;11::11\n" // IP address. - "11::11\n" // IP address. - "11:11:abcdef:0:0:0:0:0"; // No PII, it is not valid IP address format. + "example@@1234\n" // No PII, it is not valid email address. + "255.255.155.255\n" // IP address. + "aaaa123.123.45.4aaa\n" // IP address. + "11:11;11::11\n" // IP address. + "11::11\n" // IP address. + "11:11:abcdef:0:0:0:0:0\n" // No PII. + "aa:aa:aa:aa:aa:aa"; // MAC address (BSSID). std::string result = + "aaaaaaaa [SSID=1]aaaaa\n" + "aaaaaaaa<URL: 1>\n" + "<email: 1>\n" "example@@1234\n" - "255.255.355.255\n" - "11:11:abcdef:0:0:0:0:0\n"; - - EXPECT_EQ(result, SystemLogUploader::RemoveSensitiveData(data)); + "<IPv4: 1>55\n" + "aaaa<IPv4: 2>aaa\n" + "11:11;<IPv6: 1>\n" + "<IPv6: 1>\n" + "11:11:abcdef:0:0:0:0:0\n" + "aa:aa:aa:00:00:01"; + EXPECT_EQ(result, SystemLogUploader::RemoveSensitiveData(&anonymizer, data)); } } // namespace policy
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc index 4e0e1fcc..8d7913db 100644 --- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc +++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -159,13 +159,7 @@ } // namespace -// See crbug.com/576364 for details -#if defined(OS_CHROMEOS) -#define MAYBE_Basic DISABLED_Basic -#else -#define MAYBE_Basic Basic -#endif -IN_PROC_BROWSER_TEST_F(CertificateProviderApiTest, MAYBE_Basic) { +IN_PROC_BROWSER_TEST_F(CertificateProviderApiTest, Basic) { // Start an HTTPS test server that requests a client certificate. net::SpawnedTestServer::SSLOptions ssl_options; ssl_options.request_client_certificate = true; @@ -197,6 +191,9 @@ content::WebContents* const https_contents = browser()->tab_strip_model()->GetActiveWebContents(); + VLOG(1) << "Wait for the extension to respond to the certificates request."; + ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); + VLOG(1) << "Wait for the extension to receive the sign request."; ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc index 86ff346..1034dda 100644 --- a/chrome/browser/extensions/api/management/management_browsertest.cc +++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -624,8 +624,6 @@ browser()->profile())->extension_service(); ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); const char kExtensionId[] = "ogjcoiohnmldgjemafoockdghcjciccf"; - extensions::ExtensionUpdater::CheckParams params; - service->updater()->set_default_check_params(params); const size_t size_before = registry->enabled_extensions().size(); base::FilePath basedir = test_data_dir_.AppendASCII("autoupdate"); ASSERT_TRUE(registry->disabled_extensions().is_empty());
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc index 47a791c..4466ade1 100644 --- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -213,9 +213,6 @@ GURL("http://localhost/autoupdate/v2.crx"), scoped_temp_dir_.path().AppendASCII("permissions2.crx")); - extensions::ExtensionUpdater::CheckParams params; - service_->updater()->set_default_check_params(params); - extensions::TestExtensionRegistryObserver install_observer(registry_); sync_service->ProcessSyncChanges( FROM_HERE, @@ -252,9 +249,6 @@ GURL("http://localhost/autoupdate/v2.crx"), scoped_temp_dir_.path().AppendASCII("permissions2.crx")); - extensions::ExtensionUpdater::CheckParams params; - service_->updater()->set_default_check_params(params); - sync_pb::EntitySpecifics specifics; specifics.mutable_extension()->set_id(extension_id); specifics.mutable_extension()->set_enabled(false);
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc index 939fe69..695e6a1 100644 --- a/chrome/browser/extensions/updater/extension_updater.cc +++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -269,7 +269,7 @@ void ExtensionUpdater::TimerFired() { DCHECK(alive_); - CheckNow(default_params_); + CheckNow(CheckParams()); // If the user has overridden the update frequency, don't bother reporting // this. @@ -321,7 +321,7 @@ void ExtensionUpdater::DoCheckSoon() { DCHECK(will_check_soon_); - CheckNow(default_params_); + CheckNow(CheckParams()); will_check_soon_ = false; }
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h index 3cb450d..772eef6 100644 --- a/chrome/browser/extensions/updater/extension_updater.h +++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -119,12 +119,6 @@ // code should just call CheckSoon(). bool WillCheckSoon() const; - // Changes the params that are used for the automatic periodic update checks, - // as well as for explicit calls to CheckSoon. - void set_default_check_params(const CheckParams& params) { - default_params_ = params; - } - // Overrides the extension cache with |extension_cache| for testing. void SetExtensionCacheForTesting(ExtensionCache* extension_cache); @@ -271,8 +265,6 @@ std::stack<FetchedCRXFile> fetched_crx_files_; FetchedCRXFile current_crx_file_; - CheckParams default_params_; - ExtensionCache* extension_cache_; // Keeps track of when an extension tried to update itself, so we can throttle
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc index 375e7e0..3513765 100644 --- a/chrome/browser/media/android/remote/remote_media_player_manager.cc +++ b/chrome/browser/media/android/remote/remote_media_player_manager.cc
@@ -12,6 +12,8 @@ using media::MediaPlayerAndroid; +static const int MAX_POSTER_BITMAP_SIZE = 1024 * 1024; + namespace remote_media { RemoteMediaPlayerManager::RemoteMediaPlayerManager( @@ -50,6 +52,7 @@ RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id); if (player) player->OnPlayerDestroyed(); + poster_urls_.erase(player_id); BrowserMediaPlayerManager::OnDestroyPlayer(player_id); } @@ -86,27 +89,30 @@ return tab->GetAndroidId(); } -void RemoteMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) { +void RemoteMediaPlayerManager::FetchPosterBitmap(int player_id) { RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id); - - if (player && url.is_empty()) { - player->SetPosterBitmap(std::vector<SkBitmap>()); - } else { - // TODO(aberent) OnSetPoster is called when the attributes of the video - // element are parsed, which may be before OnInitialize is called. We are - // here relying on the image fetch taking longer than the delay until - // OnInitialize is called, and hence the player is created. This is not - // guaranteed. - content::WebContents::ImageDownloadCallback callback = base::Bind( - &RemoteMediaPlayerManager::DidDownloadPoster, - weak_ptr_factory_.GetWeakPtr(), player_id); - web_contents()->DownloadImage( - url, - false, // is_favicon, false so that cookies will be used. - 0, // max_bitmap_size, 0 means no limit. - false, // normal cache policy. - callback); + if (poster_urls_.count(player_id) == 0 || + poster_urls_[player_id].is_empty()) { + if (player) + player->SetPosterBitmap(std::vector<SkBitmap>()); + return; } + content::WebContents::ImageDownloadCallback callback = + base::Bind(&RemoteMediaPlayerManager::DidDownloadPoster, + weak_ptr_factory_.GetWeakPtr(), player_id); + web_contents()->DownloadImage( + poster_urls_[player_id], + false, // is_favicon, false so that cookies will be used. + MAX_POSTER_BITMAP_SIZE, // max_bitmap_size, 0 means no limit. + false, // normal cache policy. + callback); +} + +void RemoteMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) { + // OnSetPoster is called when the attibutes of the video element are parsed, + // which may be before OnInitialize is called, so we can't assume that the + // players wil exist. + poster_urls_[player_id] = url; } void RemoteMediaPlayerManager::ReleaseResources(int player_id) { @@ -171,6 +177,9 @@ Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), player_id)); Send(new MediaPlayerMsg_ConnectedToRemoteDevice(RoutingID(), player_id, casting_message)); + // The remote player will want the poster bitmap, however, to avoid wasting + // memory we don't fetch it until we are likely to need it. + FetchPosterBitmap(player_id); } void RemoteMediaPlayerManager::SwitchToLocalPlayer(int player_id) {
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.h b/chrome/browser/media/android/remote/remote_media_player_manager.h index e0cef391..fea7caa 100644 --- a/chrome/browser/media/android/remote/remote_media_player_manager.h +++ b/chrome/browser/media/android/remote/remote_media_player_manager.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_ #include <set> +#include <unordered_map> #include <vector> #include "base/macros.h" @@ -105,12 +106,15 @@ void SwapCurrentPlayer(int player_id); + void FetchPosterBitmap(int player_id); + // Contains the alternative players that are not currently in use, i.e. the // remote players for videos that are playing locally, and the local players // for videos that are playing remotely. ScopedVector<media::MediaPlayerAndroid> alternative_players_; std::set<int> players_playing_remotely_; + std::unordered_map<int, GURL> poster_urls_; base::WeakPtrFactory<RemoteMediaPlayerManager> weak_ptr_factory_;
diff --git a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc index 4821d4e..c073cf1 100644 --- a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc +++ b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
@@ -229,7 +229,9 @@ base::Process collider_server_; }; -IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, MANUAL_WorksOnApprtc) { +// Broken because of dependency updates: http://crbug.com/581283. +IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, + DISABLED_MANUAL_WorksOnApprtc) { DetectErrorsInJavaScript(); ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999")); ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089")); @@ -269,10 +271,11 @@ chrome::CloseWebContents(browser(), right_tab, false); } -#if defined(OS_LINUX) +#if 0 #define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest #else // Not implemented yet on Windows and Mac. +// Broken because of dependency updates: http://crbug.com/581283. #define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest #endif
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js index 4a5a310..800b2547 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -296,11 +296,6 @@ Constants.CustomWallpaperThumbnailSuffix, ''); WallpaperUtil.deleteWallpaperFromLocalFS(fileName); } - } else { // detail.direction == 'local_to_remote' - if (detail.action == 'deleted') { - WallpaperUtil.deleteWallpaperFromSyncFS(detail.fileEntry.name); - WallpaperUtil.deleteWallpaperFromLocalFS(detail.fileEntry.name); - } } } });
diff --git a/chrome/browser/resources/ntp4/new_incognito_tab_theme.css b/chrome/browser/resources/ntp4/new_incognito_tab_theme.css index 496b95b..62ec092 100644 --- a/chrome/browser/resources/ntp4/new_incognito_tab_theme.css +++ b/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
@@ -5,21 +5,21 @@ html { background-attachment: fixed; - background-color: ${colorBackground}; - background-position: ${backgroundBarDetached}; - background-repeat: ${backgroundTiling}; + background-color: $i18n{colorBackground}; + background-position: $i18n{backgroundBarDetached}; + background-repeat: $i18n{backgroundTiling}; height: 100%; overflow: auto; } html[hascustombackground='true'] { - background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?${themeId}); + background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$i18n{themeId}); } html[bookmarkbarattached='true'] { - background-position: ${backgroundBarAttached}; + background-position: $i18n{backgroundBarAttached}; } #attribution-img { - content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?${themeId}); + content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$i18n{themeId}); }
diff --git a/chrome/browser/resources/ntp4/new_tab_theme.css b/chrome/browser/resources/ntp4/new_tab_theme.css index 6474290..7725c97e 100644 --- a/chrome/browser/resources/ntp4/new_tab_theme.css +++ b/chrome/browser/resources/ntp4/new_tab_theme.css
@@ -1,53 +1,53 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. +/* Copyright 2012 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ html { background-attachment: fixed; - background-color: ${colorBackground}; - background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?${themeId}); - background-position: ${backgroundBarDetached}; - background-repeat: ${backgroundTiling}; + background-color: $i18n{colorBackground}; + background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$i18n{themeId}); + background-position: $i18n{backgroundBarDetached}; + background-repeat: $i18n{backgroundTiling}; } #attribution { - left: ${leftAlignAttribution}; - right: ${rightAlignAttribution}; - text-align: ${textAlignAttribution}; - display: ${displayAttribution}; + left: $i18n{leftAlignAttribution}; + right: $i18n{rightAlignAttribution}; + text-align: $i18n{textAlignAttribution}; + display: $i18n{displayAttribution}; } #attribution-img { - content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?${themeId}); + content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$i18n{themeId}); } html[bookmarkbarattached='true'] { - background-position: ${backgroundBarAttached}; + background-position: $i18n{backgroundBarAttached}; } body { - color: ${colorTextRgba}; + color: $i18n{colorTextRgba}; height: 100%; overflow: auto; } #attribution, [is='action-link'] { - color: ${colorTextLight}; + color: $i18n{colorTextLight}; } [is='action-link']:active { - color: ${colorTextRgba}; + color: $i18n{colorTextRgba}; } .page-switcher { - color: rgba(${colorText}, 0.5); + color: rgba($i18n{colorText}, 0.5); } .page-switcher:hover, .page-switcher:focus, .page-switcher.drag-target { - background-color: rgba(${colorText}, 0.06); + background-color: rgba($i18n{colorText}, 0.06); } /* Only change the background to a gradient when a promo is showing. */ @@ -55,34 +55,34 @@ .showing-login-area #page-switcher-end:focus, .showing-login-area #page-switcher-end.drag-target { background: linear-gradient(top, - rgba(${colorText}, 0) 0, - rgba(${colorText}, .01) 60px, - rgba(${colorText}, .06) 183px); + rgba($i18n{colorText}, 0) 0, + rgba($i18n{colorText}, .01) 60px, + rgba($i18n{colorText}, .06) 183px); } .tile-page-scrollbar { - background-color: ${colorTextLight}; + background-color: $i18n{colorTextLight}; } /* Footer *********************************************************************/ #footer-border { background: linear-gradient(left, - rgba(${colorSectionBorder}, 0.2), - rgba(${colorSectionBorder}, 0.3) 20%, - rgba(${colorSectionBorder}, 0.3) 80%, - rgba(${colorSectionBorder}, 0.2)); + rgba($i18n{colorSectionBorder}, 0.2), + rgba($i18n{colorSectionBorder}, 0.3) 20%, + rgba($i18n{colorSectionBorder}, 0.3) 80%, + rgba($i18n{colorSectionBorder}, 0.2)); } .dot input:focus { - background-color: ${colorBackground}; + background-color: $i18n{colorBackground}; } .thumbnail-wrapper { /* This shows through at the (rounded) thumbnail's corners. */ - background-color: ${colorSectionBorder}; + background-color: $i18n{colorSectionBorder}; } .filler .thumbnail { - border-color: ${colorBackground}; + border-color: $i18n{colorBackground}; }
diff --git a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc index 4c712e6c..6ac4d092 100644 --- a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc +++ b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
@@ -368,6 +368,33 @@ false /* expect cert status error */); } +// Tests that the Content Security Policy block-all-mixed-content +// directive stops mixed content from running. +IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, + MixedContentStrictBlocking) { + ASSERT_TRUE(https_server_.Start()); + SetUpMockCertVerifierForHttpsServer(0, net::OK); + + // Navigate to an HTTPS page that tries to run mixed content in an + // iframe, with strict mixed content blocking. + std::string replacement_path; + net::HostPortPair host_port_pair = + net::HostPortPair::FromURL(https_server_.GetURL("/")); + host_port_pair.set_host("different-host.test"); + host_resolver()->AddRule("different-host.test", + https_server_.GetURL("/").host()); + GetFilePathWithHostAndPortReplacement( + "/ssl/page_runs_insecure_content_in_iframe_with_strict_blocking.html", + host_port_pair, &replacement_path); + ui_test_utils::NavigateToURL(browser(), + https_server_.GetURL(replacement_path)); + CheckSecurityInfoForSecure( + browser()->tab_strip_model()->GetActiveWebContents(), + SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, + SecurityStateModel::NO_MIXED_CONTENT, + false /* expect cert status error */); +} + IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, BrokenHTTPS) { ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(https_server_.Start());
diff --git a/chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h b/chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h index e373587a..839d7c4 100644 --- a/chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h +++ b/chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h
@@ -7,12 +7,17 @@ #import <Cocoa/Cocoa.h> +class ManagePasswordsBubbleModel; + // Handles user interaction with the content view. @protocol ManagePasswordsBubbleContentViewDelegate<NSObject> // The user performed an action that should dismiss the bubble. - (void)viewShouldDismiss; +// Returns the model object. +@property(nonatomic, readonly) ManagePasswordsBubbleModel* model; + @end // Base class for a state of the password management bubble.
diff --git a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h index 104dab9..656a1c6 100644 --- a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h +++ b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h
@@ -44,10 +44,8 @@ // Helper delegate for testing the views of the password management bubble. @interface ContentViewDelegateMock - : NSObject<ManagePasswordsBubbleContentViewDelegate> { - @private - BOOL _dismissed; -} + : NSObject<ManagePasswordsBubbleContentViewDelegate> +@property(nonatomic) ManagePasswordsBubbleModel* model; @property(readonly, nonatomic) BOOL dismissed; @end
diff --git a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.mm b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.mm index 0155e53..cbbf146 100644 --- a/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.mm +++ b/chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.mm
@@ -110,6 +110,7 @@ @implementation ContentViewDelegateMock +@synthesize model = _model; @synthesize dismissed = _dismissed; - (void)viewShouldDismiss {
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm index 5877df79..d6df328d 100644 --- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
@@ -52,6 +52,8 @@ - (void)close { [currentController_ bubbleWillDisappear]; + // The bubble is about to be closed. It destroys the model. + model_ = nil; [super close]; } @@ -60,13 +62,11 @@ currentController_.reset(); if (model_->state() == password_manager::ui::PENDING_PASSWORD_STATE) { currentController_.reset([[SavePendingPasswordViewController alloc] - initWithModel:model_ - delegate:self]); + initWithDelegate:self]); } else if (model_->state() == password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) { currentController_.reset([[UpdatePendingPasswordViewController alloc] - initWithModel:model_ - delegate:self]); + initWithDelegate:self]); } else if (model_->state() == password_manager::ui::CONFIRMATION_STATE) { currentController_.reset( [[ManagePasswordsBubbleConfirmationViewController alloc] @@ -148,6 +148,10 @@ [self close]; } +- (ManagePasswordsBubbleModel*)model { + return model_; +} + @end @implementation ManagePasswordsBubbleController (Testing)
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm index fcc927e..627f91f 100644 --- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
@@ -81,4 +81,11 @@ [[controller() currentController] class]); } +TEST_F(ManagePasswordsBubbleControllerTest, ClearModelOnClose) { + SetUpUpdatePendingState(false); + EXPECT_TRUE(controller().model); + [controller() close]; + EXPECT_FALSE(controller().model); +} + } // namespace
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h index a5c0cd8..02e98f4 100644 --- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h +++ b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.h
@@ -10,18 +10,14 @@ #include "base/mac/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/passwords/base_passwords_content_view_controller.h" -class ManagePasswordsBubbleModel; @class PasswordsListViewController; // Base class for the views that offer to save/update the user's password. @interface PendingPasswordViewController : ManagePasswordsBubbleContentViewController<NSTextViewDelegate> { @private - ManagePasswordsBubbleModel* model_; // weak base::scoped_nsobject<NSButton> closeButton_; } -- (id)initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate; // Creates a controller for showing username/password and returns its view. - (NSView*)createPasswordView;
diff --git a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm index 588462a..97a838e 100644 --- a/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/pending_password_view_controller.mm
@@ -22,18 +22,12 @@ @implementation PendingPasswordViewController -- (id)initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate { - if (([super initWithDelegate:delegate])) { - model_ = model; - } - return self; -} - - (BOOL)textView:(NSTextView*)textView clickedOnLink:(id)link atIndex:(NSUInteger)charIndex { - model_->OnBrandLinkClicked(); + ManagePasswordsBubbleModel* model = [self model]; + if (model) + model->OnBrandLinkClicked(); [delegate_ viewShouldDismiss]; return YES; } @@ -90,8 +84,9 @@ [view addSubview:closeButton_]; // Title. + ManagePasswordsBubbleModel* model = [self model]; HyperlinkTextView* titleView = TitleLabelWithLink( - model_->title(), model_->title_brand_link_range(), self); + model->title(), model->title_brand_link_range(), self); // Force the text to wrap to fit in the bubble size. int titleRightPadding = @@ -177,7 +172,7 @@ } - (ManagePasswordsBubbleModel*)model { - return model_; + return [delegate_ model]; } @end
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h index 04b2fe1..d596bab1 100644 --- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h +++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.h
@@ -18,9 +18,7 @@ base::scoped_nsobject<NSButton> neverButton_; base::scoped_nsobject<PasswordsListViewController> passwordItem_; } -- (SavePendingPasswordViewController*) -initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate; + - (NSView*)createPasswordView; - (NSArray*)createButtonsAndAddThemToView:(NSView*)view; @end
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm index 1b7ff8e4..537370c 100644 --- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
@@ -16,25 +16,21 @@ @implementation SavePendingPasswordViewController -- (SavePendingPasswordViewController*) -initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate { - self = [super initWithModel:model - delegate:delegate]; - return self; -} - - (NSButton*)defaultButton { return saveButton_; } - (void)onSaveClicked:(id)sender { - self.model->OnSaveClicked(); + ManagePasswordsBubbleModel* model = self.model; + if (model) + model->OnSaveClicked(); [delegate_ viewShouldDismiss]; } - (void)onNeverForThisSiteClicked:(id)sender { - self.model->OnNeverForThisSiteClicked(); + ManagePasswordsBubbleModel* model = self.model; + if (model) + model->OnNeverForThisSiteClicked(); [delegate_ viewShouldDismiss]; }
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm index d4cfef7..61a8f2d 100644 --- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller_unittest.mm
@@ -32,10 +32,10 @@ SavePendingPasswordViewController* controller() { if (!controller_) { + [delegate() setModel:GetModelAndCreateIfNull()]; controller_.reset([[SavePendingPasswordViewController alloc] - initWithModel:GetModelAndCreateIfNull() - delegate:delegate()]); - [controller_ loadView]; + initWithDelegate:delegate()]); + [controller_ view]; } return controller_.get(); } @@ -86,4 +86,16 @@ EXPECT_FALSE([controller() createPasswordView]); } +TEST_F(SavePendingPasswordViewControllerTest, CloseBubbleAndHandleClick) { + // A user may press mouse down, some navigation closes the bubble, mouse up + // still sends the action. + SetUpSavePendingState(false); + EXPECT_CALL(*ui_controller(), SavePassword()).Times(0); + EXPECT_CALL(*ui_controller(), NeverSavePassword()).Times(0); + [controller() bubbleWillDisappear]; + [delegate() setModel:nil]; + [controller().neverButton performClick:nil]; + [controller().saveButton performClick:nil]; +} + } // namespace
diff --git a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h index a1f4602..b6853d0 100644 --- a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h +++ b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.h
@@ -21,9 +21,7 @@ base::scoped_nsobject<CredentialsSelectionView> passwordWithUsernameSelectionItem_; } -- (UpdatePendingPasswordViewController*) -initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate; + - (NSView*)createPasswordView; - (NSArray*)createButtonsAndAddThemToView:(NSView*)view; @end
diff --git a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.mm index 4bf4d42..186e38a 100644 --- a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller.mm
@@ -17,30 +17,28 @@ @implementation UpdatePendingPasswordViewController -- (UpdatePendingPasswordViewController*) -initWithModel:(ManagePasswordsBubbleModel*)model - delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate { - self = [super initWithModel:model delegate:delegate]; - return self; -} - - (NSButton*)defaultButton { return updateButton_; } - (void)onUpdateClicked:(id)sender { - if (passwordWithUsernameSelectionItem_) { - // Multi account case. - self.model->OnUpdateClicked( - *[passwordWithUsernameSelectionItem_ getSelectedCredentials]); - } else { - self.model->OnUpdateClicked(self.model->pending_password()); + ManagePasswordsBubbleModel* model = [self model]; + if (model) { + if (passwordWithUsernameSelectionItem_) { + // Multi account case. + model->OnUpdateClicked( + *[passwordWithUsernameSelectionItem_ getSelectedCredentials]); + } else { + model->OnUpdateClicked(model->pending_password()); + } } [delegate_ viewShouldDismiss]; } - (void)onNopeClicked:(id)sender { - self.model->OnNopeUpdateClicked(); + ManagePasswordsBubbleModel* model = [self model]; + if (model) + model->OnNopeUpdateClicked(); [delegate_ viewShouldDismiss]; }
diff --git a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm index ac3df4c..73efa29 100644 --- a/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/passwords/update_pending_password_view_controller_unittest.mm
@@ -36,10 +36,10 @@ UpdatePendingPasswordViewController* controller() { if (!controller_) { + [delegate() setModel:GetModelAndCreateIfNull()]; controller_.reset([[UpdatePendingPasswordViewController alloc] - initWithModel:GetModelAndCreateIfNull() - delegate:delegate()]); - [controller_ loadView]; + initWithDelegate:delegate()]); + [controller_ view]; } return controller_.get(); } @@ -92,4 +92,16 @@ [[controller() createPasswordView] class]); } +TEST_F(UpdatePendingPasswordViewControllerTest, CloseBubbleAndHandleClick) { + // A user may press mouse down, some navigation closes the bubble, mouse up + // still sends the action. + SetUpUpdatePendingState(false); + EXPECT_CALL(*ui_controller(), UpdatePassword(_)).Times(0); + EXPECT_CALL(*ui_controller(), OnNopeUpdateClicked()).Times(0); + [controller() bubbleWillDisappear]; + [delegate() setModel:nil]; + [controller().updateButton performClick:nil]; + [controller().noButton performClick:nil]; +} + } // namespace
diff --git a/chrome/browser/ui/passwords/manage_passwords_state.cc b/chrome/browser/ui/passwords/manage_passwords_state.cc index 8f2cfcc3..6d4508c 100644 --- a/chrome/browser/ui/passwords/manage_passwords_state.cc +++ b/chrome/browser/ui/passwords/manage_passwords_state.cc
@@ -152,10 +152,15 @@ void ManagePasswordsState::OnPasswordAutofilled( const PasswordFormMap& password_form_map, const GURL& origin) { - // TODO(vabr): Revert back to DCHECK once http://crbug.com/486931 is fixed. - CHECK(!password_form_map.empty()); + DCHECK(!password_form_map.empty()); ClearData(); - if (password_form_map.begin()->second->is_public_suffix_match) { + bool only_PSL_matches = + find_if(password_form_map.begin(), password_form_map.end(), + [](const std::pair<const base::string16, + scoped_ptr<autofill::PasswordForm>>& p) { + return !p.second->is_public_suffix_match; + }) == password_form_map.end(); + if (only_PSL_matches) { // Don't show the UI for PSL matched passwords. They are not stored for this // page and cannot be deleted. origin_ = GURL();
diff --git a/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc index 972fb38..1c8b56d4 100644 --- a/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc +++ b/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc
@@ -364,6 +364,31 @@ TestAllUpdates(); } +TEST_F(ManagePasswordsStateTest, ActiveOnMixedPSLAndNonPSLMatched) { + autofill::PasswordFormMap password_form_map; + password_form_map.insert(std::make_pair( + test_local_form().username_value, + make_scoped_ptr(new autofill::PasswordForm(test_local_form())))); + autofill::PasswordForm psl_matched_test_form = test_local_form(); + psl_matched_test_form.is_public_suffix_match = true; + password_form_map.insert(std::make_pair( + psl_matched_test_form.username_value, + make_scoped_ptr(new autofill::PasswordForm(psl_matched_test_form)))); + GURL origin("https://example.com"); + passwords_data().OnPasswordAutofilled(password_form_map, origin); + + EXPECT_THAT(passwords_data().GetCurrentForms(), + ElementsAre(Pointee(test_local_form()))); + EXPECT_THAT(passwords_data().federated_credentials_forms(), IsEmpty()); + EXPECT_EQ(password_manager::ui::MANAGE_STATE, passwords_data().state()); + EXPECT_EQ(origin, passwords_data().origin()); + + // |passwords_data| should hold a separate copy of test_local_form(). + EXPECT_THAT(passwords_data().GetCurrentForms(), + Not(Contains(&test_local_form()))); + TestAllUpdates(); +} + TEST_F(ManagePasswordsStateTest, InactiveOnPSLMatched) { autofill::PasswordForm psl_matched_test_form = test_local_form(); psl_matched_test_form.is_public_suffix_match = true;
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.cc b/chrome/browser/ui/views/passwords/manage_password_items_view.cc index cd35ea5..b509ea2f 100644 --- a/chrome/browser/ui/views/passwords/manage_password_items_view.cc +++ b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
@@ -267,8 +267,9 @@ : model_(manage_passwords_bubble_model) { int fixed_height = PasswordFormRow::GetFixedHeight(model_->state()); for (const autofill::PasswordForm* password_form : password_forms) { - password_forms_rows_.push_back( - new PasswordFormRow(this, password_form, fixed_height)); + if (!password_form->is_public_suffix_match) + password_forms_rows_.push_back( + new PasswordFormRow(this, password_form, fixed_height)); } AddRows(); }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc index 610bbc4..cd023867 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -427,7 +427,15 @@ // If we have a list of passwords to store for the current site, display // them to the user for management. Otherwise, render a "No passwords for // this site" message. - if (!parent_->model()->local_credentials().empty()) { + + bool only_PSL_matches = + find_if(parent_->model()->local_credentials().begin(), + parent_->model()->local_credentials().end(), + [](const autofill::PasswordForm* form) { + return !form->is_public_suffix_match; + }) == parent_->model()->local_credentials().end(); + + if (!only_PSL_matches) { ManagePasswordItemsView* item = new ManagePasswordItemsView( parent_->model(), parent_->model()->local_credentials().get()); layout->StartRowWithPadding(0, SINGLE_VIEW_COLUMN_SET, 0,
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index df78320..e74b0fc 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -553,7 +553,7 @@ : SkColorSetRGB(0x32, 0x32, 0x32); // Generate the replacements. - std::map<base::StringPiece, std::string> substitutions; + ui::TemplateReplacements substitutions; // Cache-buster for background. substitutions["themeId"] = @@ -605,7 +605,7 @@ SkColorGetB(color_header)); // Generate the replacements. - std::map<base::StringPiece, std::string> substitutions; + ui::TemplateReplacements substitutions; // Cache-buster for background. substitutions["themeId"] =
diff --git a/chrome/browser/web_dev_style/css_checker.py b/chrome/browser/web_dev_style/css_checker.py index 3713561e..7d03a60 100644 --- a/chrome/browser/web_dev_style/css_checker.py +++ b/chrome/browser/web_dev_style/css_checker.py
@@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -52,7 +52,7 @@ return re.sub(re.compile(r'--[\d\w-]+: {.*?};', re.DOTALL), '', s) def _remove_template_expressions(s): - return re.sub(re.compile(r'\${[^}]*}', re.DOTALL), '', s) + return re.sub(re.compile(r'\$i18n{[^}]*}', re.DOTALL), '', s) def _remove_grit(s): grit_reg = re.compile(r"""
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 260b68b4..7720c68 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -1130,6 +1130,7 @@ '../components/components.gyp:cloud_policy_proto', '../components/components.gyp:drive', '../components/components.gyp:drive_chromeos', + '../components/components.gyp:feedback_component', '../components/components.gyp:flags_ui', '../components/components.gyp:login', '../components/components.gyp:onc_component',
diff --git a/chrome/installer/test/alternate_version_generator.cc b/chrome/installer/test/alternate_version_generator.cc index c0ec333..211b1e5 100644 --- a/chrome/installer/test/alternate_version_generator.cc +++ b/chrome/installer/test/alternate_version_generator.cc
@@ -425,8 +425,8 @@ return false; } DCHECK(modified); - return base::WriteFile(manifest, &contents[0], contents.size()) == - contents.size(); + int written = base::WriteFile(manifest, &contents[0], contents.size()); + return written != -1 && static_cast<size_t>(written) == contents.size(); } bool IncrementNewVersion(upgrade_test::Direction direction,
diff --git a/chrome/installer/upgrade_test.gyp b/chrome/installer/upgrade_test.gyp index 07b283e..1a05535 100644 --- a/chrome/installer/upgrade_test.gyp +++ b/chrome/installer/upgrade_test.gyp
@@ -4,6 +4,7 @@ { 'variables': { + 'chromium_code': 1, 'branding_dir': '../app/theme/<(branding_path_component)', 'version_py': '<(DEPTH)/build/util/version.py', 'version_path': '../../chrome/VERSION',
diff --git a/chrome/renderer/resources/OWNERS b/chrome/renderer/resources/OWNERS new file mode 100644 index 0000000..cb68f46 --- /dev/null +++ b/chrome/renderer/resources/OWNERS
@@ -0,0 +1,8 @@ +bauerb@chromium.org +dbeam@chromium.org +estade@chromium.org +nkostylev@chromium.org +pam@chromium.org +xiyuan@chromium.org + +per-file offline.js=edwardjung@chromium.org
diff --git a/chrome/renderer/resources/default_100_percent/offline/100-offline-sprite.png b/chrome/renderer/resources/default_100_percent/offline/100-offline-sprite.png index 068d4a1..06348354 100644 --- a/chrome/renderer/resources/default_100_percent/offline/100-offline-sprite.png +++ b/chrome/renderer/resources/default_100_percent/offline/100-offline-sprite.png Binary files differ
diff --git a/chrome/renderer/resources/default_200_percent/offline/200-offline-sprite.png b/chrome/renderer/resources/default_200_percent/offline/200-offline-sprite.png index f321c354..3a1e92e 100644 --- a/chrome/renderer/resources/default_200_percent/offline/200-offline-sprite.png +++ b/chrome/renderer/resources/default_200_percent/offline/200-offline-sprite.png Binary files differ
diff --git a/chrome/renderer/resources/neterror.css b/chrome/renderer/resources/neterror.css index 246c8a9..4ebd6c4 100644 --- a/chrome/renderer/resources/neterror.css +++ b/chrome/renderer/resources/neterror.css
@@ -334,6 +334,17 @@ } /* Offline page */ +.offline { + transition: -webkit-filter 1.5s cubic-bezier(0.65, 0.05, 0.36, 1), + background-color 1.5s cubic-bezier(0.65, 0.05, 0.36, 1); + will-change: -webkit-filter, background-color; +} + +.offline.inverted { + -webkit-filter: invert(100%); + background-color: #000; +} + .offline .interstitial-wrapper { color: #2b2b2b; font-size: 1em;
diff --git a/chrome/renderer/resources/offline.js b/chrome/renderer/resources/offline.js index e16dfa6..21bd286 100644 --- a/chrome/renderer/resources/offline.js +++ b/chrome/renderer/resources/offline.js
@@ -47,7 +47,8 @@ this.activated = false; this.crashed = false; this.paused = false; - + this.inverted = false; + this.invertTimer = 0; this.resizeTimerId_ = null; this.playCount = 0; @@ -111,6 +112,8 @@ GAP_COEFFICIENT: 0.6, GRAVITY: 0.6, INITIAL_JUMP_VELOCITY: 12, + INVERT_FADE_DURATION: 12000, + INVERT_DISTANCE: 700, MAX_CLOUDS: 6, MAX_OBSTACLE_LENGTH: 3, MAX_OBSTACLE_DUPLICATION: 2, @@ -142,6 +145,7 @@ CONTAINER: 'runner-container', CRASHED: 'crashed', ICON: 'icon-offline', + INVERTED: 'inverted', SNACKBAR: 'snackbar', SNACKBAR_SHOW: 'snackbar-show', TOUCH_CONTROLLER: 'controller' @@ -158,20 +162,24 @@ CACTUS_SMALL: {x: 228, y: 2}, CLOUD: {x: 86, y: 2}, HORIZON: {x: 2, y: 54}, + MOON: {x: 484, y: 2}, PTERODACTYL: {x: 134, y: 2}, RESTART: {x: 2, y: 2}, - TEXT_SPRITE: {x: 484, y: 2}, - TREX: {x: 677, y: 2} + TEXT_SPRITE: {x: 655, y: 2}, + TREX: {x: 848, y: 2}, + STAR: {x: 645, y: 2} }, HDPI: { - CACTUS_LARGE: {x: 652,y: 2}, - CACTUS_SMALL: {x: 446,y: 2}, - CLOUD: {x: 166,y: 2}, - HORIZON: {x: 2,y: 104}, - PTERODACTYL: {x: 260,y: 2}, - RESTART: {x: 2,y: 2}, - TEXT_SPRITE: {x: 954,y: 2}, - TREX: {x: 1338,y: 2} + CACTUS_LARGE: {x: 652, y: 2}, + CACTUS_SMALL: {x: 446, y: 2}, + CLOUD: {x: 166, y: 2}, + HORIZON: {x: 2, y: 104}, + MOON: {x: 954, y: 2}, + PTERODACTYL: {x: 260, y: 2}, + RESTART: {x: 2, y: 2}, + TEXT_SPRITE: {x: 1294, y: 2}, + TREX: {x: 1678, y: 2}, + STAR: {x: 1276, y: 2} } }; @@ -525,7 +533,8 @@ this.horizon.update(0, this.currentSpeed, hasObstacles); } else { deltaTime = !this.started ? 0 : deltaTime; - this.horizon.update(deltaTime, this.currentSpeed, hasObstacles); + this.horizon.update(deltaTime, this.currentSpeed, hasObstacles, + this.inverted); } // Check for collisions. @@ -542,12 +551,34 @@ this.gameOver(); } - var playAcheivementSound = this.distanceMeter.update(deltaTime, + var playAchievementSound = this.distanceMeter.update(deltaTime, Math.ceil(this.distanceRan)); - if (playAcheivementSound) { + if (playAchievementSound) { this.playSound(this.soundFx.SCORE); } + + // Night mode. + if (this.invertTimer > this.config.INVERT_FADE_DURATION) { + this.invertTimer = 0; + this.invertTrigger = false; + this.invert(); + } else if (this.invertTimer) { + this.invertTimer += deltaTime; + } else { + var actualDistance = + this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan)); + + if (actualDistance > 0) { + this.invertTrigger = !(actualDistance % + this.config.INVERT_DISTANCE); + + if (this.invertTrigger && this.invertTimer === 0) { + this.invertTimer += deltaTime; + this.invert(); + } + } + } } if (!this.crashed) { @@ -774,7 +805,6 @@ this.crashed = false; this.distanceRan = 0; this.setSpeed(this.config.SPEED); - this.time = getTimeStamp(); this.containerEl.classList.remove(Runner.classes.CRASHED); this.clearCanvas(); @@ -782,7 +812,7 @@ this.horizon.reset(); this.tRex.reset(); this.playSound(this.soundFx.BUTTON_PRESS); - + this.invert(true); this.update(); } }, @@ -791,7 +821,8 @@ * Pause the game if the tab is not in focus. */ onVisibilityChange: function(e) { - if (document.hidden || document.webkitHidden || e.type == 'blur') { + if (document.hidden || document.webkitHidden || e.type == 'blur' || + document.visibilityState != 'visible') { this.stop(); } else if (!this.crashed) { this.tRex.reset(); @@ -810,6 +841,21 @@ sourceNode.connect(this.audioContext.destination); sourceNode.start(0); } + }, + + /** + * Inverts the current page / canvas colors. + * @param {boolean} Whether to reset colors. + */ + invert: function(reset) { + if (reset) { + document.body.classList.toggle(Runner.classes.INVERTED, false); + this.invertTimer = 0; + this.inverted = false; + } else { + this.inverted = document.body.classList.toggle(Runner.classes.INVERTED, + this.invertTrigger); + } } }; @@ -1173,9 +1219,10 @@ * @param {Object} dimensions * @param {number} gapCoefficient Mutipler in determining the gap. * @param {number} speed + * @param {number} opt_xOffset */ function Obstacle(canvasCtx, type, spriteImgPos, dimensions, - gapCoefficient, speed) { + gapCoefficient, speed, opt_xOffset) { this.canvasCtx = canvasCtx; this.spritePos = spriteImgPos; @@ -1184,7 +1231,7 @@ this.size = getRandomNum(1, Obstacle.MAX_OBSTACLE_LENGTH); this.dimensions = dimensions; this.remove = false; - this.xPos = 0; + this.xPos = dimensions.WIDTH + (opt_xOffset || 0); this.yPos = 0; this.width = 0; this.collisionBoxes = []; @@ -1225,7 +1272,6 @@ } this.width = this.typeConfig.width * this.size; - this.xPos = this.dimensions.WIDTH - this.width; // Check if obstacle can be positioned at various heights. if (Array.isArray(this.typeConfig.yPos)) { @@ -1806,6 +1852,7 @@ this.defaultString = ''; this.flashTimer = 0; this.flashIterations = 0; + this.invertTrigger = false; this.config = DistanceMeter.config; this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; @@ -1949,7 +1996,6 @@ if (!this.acheivement) { distance = this.getActualDistance(distance); - // Score has gone beyond the initial digit count. if (distance > this.maxScore && this.maxScoreUnits == this.config.MAX_DISTANCE_UNITS) { @@ -2002,7 +2048,6 @@ } this.drawHighScore(); - return playSound; }, @@ -2140,6 +2185,162 @@ //****************************************************************************** /** + * Nightmode shows a moon and stars on the horizon. + */ +function NightMode(canvas, spritePos, containerWidth) { + this.spritePos = spritePos; + this.canvas = canvas; + this.canvasCtx = canvas.getContext('2d'); + this.xPos = containerWidth - 50; + this.yPos = 30; + this.currentPhase = 0; + this.opacity = 0; + this.containerWidth = containerWidth; + this.stars = []; + this.drawStars = false; + this.placeStars(); +}; + +/** + * @enum {number} + */ +NightMode.config = { + FADE_SPEED: 0.035, + HEIGHT: 40, + MOON_SPEED: 0.25, + NUM_STARS: 2, + STAR_SIZE: 9, + STAR_SPEED: 0.3, + STAR_MAX_Y: 70, + WIDTH: 20 +}; + +NightMode.phases = [140, 120, 100, 60, 40, 20, 0]; + +NightMode.prototype = { + /** + * Update moving moon, changing phases. + * @param {boolean} activated Whether night mode is activated. + * @param {number} delta + */ + update: function(activated, delta) { + // Moon phase. + if (activated && this.opacity == 0) { + this.currentPhase++; + + if (this.currentPhase >= NightMode.phases.length) { + this.currentPhase = 0; + } + } + + // Fade in / out. + if (activated && (this.opacity < 1 || this.opacity == 0)) { + this.opacity += NightMode.config.FADE_SPEED; + } else if (this.opacity > 0) { + this.opacity -= NightMode.config.FADE_SPEED; + } + + // Set moon positioning. + if (this.opacity > 0) { + this.xPos = this.updateXPos(this.xPos, NightMode.config.MOON_SPEED); + + // Update stars. + if (this.drawStars) { + for (var i = 0; i < NightMode.config.NUM_STARS; i++) { + this.stars[i].x = this.updateXPos(this.stars[i].x, + NightMode.config.STAR_SPEED); + } + } + this.draw(); + } else { + this.opacity = 0; + this.placeStars(); + } + this.drawStars = true; + }, + + updateXPos: function(currentPos, speed) { + if (currentPos < -NightMode.config.WIDTH) { + currentPos = this.containerWidth; + } else { + currentPos -= speed; + } + return currentPos; + }, + + draw: function() { + var moonSourceWidth = this.currentPhase == 3 ? NightMode.config.WIDTH * 2 : + NightMode.config.WIDTH; + var moonSourceHeight = NightMode.config.HEIGHT; + var moonSourceX = this.spritePos.x + NightMode.phases[this.currentPhase]; + var moonOutputWidth = moonSourceWidth; + var starSize = NightMode.config.STAR_SIZE; + var starSourceX = Runner.spriteDefinition.LDPI.STAR.x; + + if (IS_HIDPI) { + moonSourceWidth *= 2; + moonSourceHeight *= 2; + moonSourceX = this.spritePos.x + + (NightMode.phases[this.currentPhase] * 2); + starSize *= 2; + starSourceX = Runner.spriteDefinition.HDPI.STAR.x; + } + + this.canvasCtx.save(); + this.canvasCtx.globalAlpha = this.opacity; + + // Stars. + if (this.drawStars) { + for (var i = 0; i < NightMode.config.NUM_STARS; i++) { + this.canvasCtx.drawImage(Runner.imageSprite, + starSourceX, this.stars[i].sourceY, starSize, starSize, + Math.round(this.stars[i].x), this.stars[i].y, + NightMode.config.STAR_SIZE, NightMode.config.STAR_SIZE); + } + } + + // Moon. + this.canvasCtx.drawImage(Runner.imageSprite, moonSourceX, + this.spritePos.y, moonSourceWidth, moonSourceHeight, + Math.round(this.xPos), this.yPos, + moonOutputWidth, NightMode.config.HEIGHT); + + this.canvasCtx.globalAlpha = 1; + this.canvasCtx.restore(); + }, + + // Do star placement. + placeStars: function() { + var segmentSize = Math.round(this.containerWidth / + NightMode.config.NUM_STARS); + + for (var i = 0; i < NightMode.config.NUM_STARS; i++) { + this.stars[i] = {}; + this.stars[i].x = getRandomNum(segmentSize * i, segmentSize * (i + 1)); + this.stars[i].y = getRandomNum(0, NightMode.config.STAR_MAX_Y); + + if (IS_HIDPI) { + this.stars[i].sourceY = Runner.spriteDefinition.HDPI.STAR.y + + NightMode.config.STAR_SIZE * 2 * i; + } else { + this.stars[i].sourceY = Runner.spriteDefinition.LDPI.STAR.y + + NightMode.config.STAR_SIZE * i; + } + } + }, + + reset: function() { + this.currentPhase = 0; + this.opacity = 0; + this.update(false); + } + +}; + + +//****************************************************************************** + +/** * Horizon Line. * Consists of two connecting lines. Randomly assigns a flat / bumpy horizon. * @param {HTMLCanvasElement} canvas @@ -2287,6 +2488,7 @@ this.horizonOffsets = [0, 0]; this.cloudFrequency = this.config.CLOUD_FREQUENCY; this.spritePos = spritePos; + this.nightMode = null; // Cloud this.clouds = []; @@ -2294,7 +2496,6 @@ // Horizon this.horizonLine = null; - this.init(); }; @@ -2319,6 +2520,8 @@ init: function() { this.addCloud(); this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON); + this.nightMode = new NightMode(this.canvas, this.spritePos.MOON, + this.dimensions.WIDTH); }, /** @@ -2327,10 +2530,12 @@ * @param {boolean} updateObstacles Used as an override to prevent * the obstacles from being updated / added. This happens in the * ease in section. + * @param {boolean} showNightMode Night mode activated. */ - update: function(deltaTime, currentSpeed, updateObstacles) { + update: function(deltaTime, currentSpeed, updateObstacles, showNightMode) { this.runningTime += deltaTime; this.horizonLine.update(deltaTime, currentSpeed); + this.nightMode.update(showNightMode); this.updateClouds(deltaTime, currentSpeed); if (updateObstacles) { @@ -2365,6 +2570,8 @@ this.clouds = this.clouds.filter(function(obj) { return !obj.remove; }); + } else { + this.addCloud(); } }, @@ -2404,6 +2611,10 @@ } }, + removeFirstObstacle: function() { + this.obstacles.shift(); + }, + /** * Add a new obstacle. * @param {number} currentSpeed @@ -2422,7 +2633,7 @@ this.obstacles.push(new Obstacle(this.canvasCtx, obstacleType, obstacleSpritePos, this.dimensions, - this.gapCoefficient, currentSpeed)); + this.gapCoefficient, currentSpeed, obstacleType.width)); this.obstacleHistory.unshift(obstacleType.type); @@ -2454,6 +2665,7 @@ reset: function() { this.obstacles = []; this.horizonLine.reset(); + this.nightMode.reset(); }, /**
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index 46483ff..3ed91b4 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc
@@ -67,9 +67,10 @@ ServiceSandboxedProcessLauncherDelegate() {} bool PreSpawnTarget(sandbox::TargetPolicy* policy) override { - // Service process may run as windows service and it fails to create a - // window station. - return policy->SetAlternateDesktop(false) == sandbox::SBOX_ALL_OK; + // Ignore result of SetAlternateDesktop. Service process may run as windows + // service and it fails to create a window station. + base::IgnoreResult(policy->SetAlternateDesktop(false)); + return true; } private:
diff --git a/chrome/test/base/tracing_browsertest.cc b/chrome/test/base/tracing_browsertest.cc index 1b953594..69956069 100644 --- a/chrome/test/base/tracing_browsertest.cc +++ b/chrome/test/base/tracing_browsertest.cc
@@ -61,12 +61,22 @@ MemoryDumpManager::kTraceCategory, event_name, 10)); - GURL url2("chrome://credits/"); + // Create and destroy renderers while tracing is enabled. + GURL url2("chrome://credits"); ui_test_utils::NavigateToURLWithDisposition( browser(), url2, NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); ASSERT_NO_FATAL_FAILURE(ExecuteJavascriptOnCurrentTab()); + // Close the current tab. + browser()->tab_strip_model()->CloseSelectedTabs(); + + GURL url3("chrome://settings"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url3, CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + ASSERT_NO_FATAL_FAILURE(ExecuteJavascriptOnCurrentTab()); + EXPECT_TRUE(WaitForWatchEvent(no_timeout)); ASSERT_TRUE(EndTracing(&json_events));
diff --git a/chrome/test/data/ssl/page_runs_insecure_content_in_iframe_with_strict_blocking.html b/chrome/test/data/ssl/page_runs_insecure_content_in_iframe_with_strict_blocking.html new file mode 100644 index 0000000..a5e8b3b --- /dev/null +++ b/chrome/test/data/ssl/page_runs_insecure_content_in_iframe_with_strict_blocking.html
@@ -0,0 +1,10 @@ +<html> +<head><title>Page that runs insecure content in an iframe with strict blocking</title></head> +<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content"> +<body> +This page contains an iframe which loads contents over an http connection, +which would cause insecure content when this page is loaded over https, but +mixed content is strictly blocked with CSP.<br> +<iframe src="https://REPLACE_WITH_HOST_AND_PORT/ssl/iframe_with_insecure_content.html"/> +</body> +</html>
diff --git a/chrome/test/remoting/webapp_javascript_unittest.cc b/chrome/test/remoting/webapp_javascript_unittest.cc index 017a139..676daa9 100644 --- a/chrome/test/remoting/webapp_javascript_unittest.cc +++ b/chrome/test/remoting/webapp_javascript_unittest.cc
@@ -12,8 +12,9 @@ namespace remoting { -// Flakily times out on Win7 Tests (dbg): https://crbug.com/504204. -#if defined(OS_WIN) && !defined(NDEBUG) +// Flakily times out on Win7 Tests (dbg) and Linux Tests (dbg)(1): +// https://crbug.com/504204. +#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(NDEBUG) #define MAYBE_Remoting_Webapp_Js_Unittest DISABLED_Remoting_Webapp_Js_Unittest #else #define MAYBE_Remoting_Webapp_Js_Unittest Remoting_Webapp_Js_Unittest
diff --git a/components/arc/common/notifications.mojom b/components/arc/common/notifications.mojom index 6ee8f23..4d3eacfe 100644 --- a/components/arc/common/notifications.mojom +++ b/components/arc/common/notifications.mojom
@@ -27,6 +27,11 @@ MAX = PROGRESS }; +struct ArcNotificationButton { + // Title + string label; +}; + struct ArcNotificationData { // Identifier of notification string key; @@ -48,6 +53,8 @@ int32 progress_current; // The maximum value of progress. int32 progress_max; + // Action buttons + array<ArcNotificationButton> buttons; }; interface NotificationsHost {
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index 65ed75ac..23e11ebc 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -20,8 +20,10 @@ #include "content/public/browser/navigation_details.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/site_instance.h" #include "ipc/ipc_message_macros.h" +#include "ui/gfx/geometry/size_f.h" namespace autofill { @@ -147,6 +149,19 @@ RendererShouldClearPreviewedForm(); } +gfx::RectF ContentAutofillDriver::TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) { + gfx::Point orig_point(bounding_box.x(), bounding_box.y()); + gfx::Point transformed_point; + transformed_point = + render_frame_host_->GetView()->TransformPointToRootCoordSpace(orig_point); + + gfx::RectF new_box; + new_box.SetRect(transformed_point.x(), transformed_point.y(), + bounding_box.width(), bounding_box.height()); + return new_box; +} + bool ContentAutofillDriver::HandleMessage(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ContentAutofillDriver, message)
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index b9e9329..61bc690 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -61,6 +61,8 @@ void RendererShouldPreviewFieldWithValue( const base::string16& value) override; void PopupHidden() override; + gfx::RectF TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) override; // Handles a message that came from the associated render frame. bool HandleMessage(const IPC::Message& message);
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h index 82e0f12..cbead57 100644 --- a/components/autofill/core/browser/autofill_driver.h +++ b/components/autofill/core/browser/autofill_driver.h
@@ -17,6 +17,10 @@ class URLRequestContextGetter; } +namespace gfx { +class RectF; +} + namespace autofill { class FormStructure; @@ -89,6 +93,12 @@ // Informs the renderer that the popup has been hidden. virtual void PopupHidden() = 0; + + // Transform bounding box coordinates to real viewport coordinates. In + // the case of a page spanning multiple renderer processes, subframe + // renderers cannot do this transformation themselves. + virtual gfx::RectF TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) = 0; }; } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h index 6c9d523..8295440e 100644 --- a/components/autofill/core/browser/autofill_field.h +++ b/components/autofill/core/browser/autofill_field.h
@@ -53,8 +53,8 @@ void set_previously_autofilled(bool previously_autofilled) { previously_autofilled_ = previously_autofilled; } - void set_parseable_name(base::string16 parseable_name) { - parseable_name_ = std::move(parseable_name); + void set_parseable_name(const base::string16& parseable_name) { + parseable_name_ = parseable_name; } // This function automatically chooses between server and heuristic autofill
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index fad9ab5..ff6f123 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -401,7 +401,9 @@ std::vector<Suggestion> suggestions; - external_delegate_->OnQuery(query_id, form, field, bounding_box); + gfx::RectF transformed_box = + driver_->TransformBoundingBoxToViewportCoordinates(bounding_box); + external_delegate_->OnQuery(query_id, form, field, transformed_box); // Need to refresh models before using the form_event_loggers. bool is_autofill_possible = RefreshDataModels();
diff --git a/components/autofill/core/browser/test_autofill_driver.cc b/components/autofill/core/browser/test_autofill_driver.cc index 38a83ed..906b55e 100644 --- a/components/autofill/core/browser/test_autofill_driver.cc +++ b/components/autofill/core/browser/test_autofill_driver.cc
@@ -6,6 +6,7 @@ #include "base/test/sequenced_worker_pool_owner.h" #include "base/threading/sequenced_worker_pool.h" +#include "ui/gfx/geometry/rect_f.h" namespace autofill { @@ -71,4 +72,9 @@ void TestAutofillDriver::PopupHidden() { } +gfx::RectF TestAutofillDriver::TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) { + return bounding_box; +} + } // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_driver.h b/components/autofill/core/browser/test_autofill_driver.h index 6282fa5..132196c 100644 --- a/components/autofill/core/browser/test_autofill_driver.h +++ b/components/autofill/core/browser/test_autofill_driver.h
@@ -44,6 +44,8 @@ void RendererShouldPreviewFieldWithValue( const base::string16& value) override; void PopupHidden() override; + gfx::RectF TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) override; // Methods that tests can use to specialize functionality.
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc index 0ac9e33..5f8cbbf 100644 --- a/components/autofill/core/common/password_form.cc +++ b/components/autofill/core/common/password_form.cc
@@ -83,13 +83,10 @@ skip_zero_click(false), layout(Layout::LAYOUT_OTHER), was_parsed_using_autofill_predictions(false), - is_alive(true), is_public_suffix_match(false), is_affiliation_based_match(false) {} PasswordForm::~PasswordForm() { - CHECK(is_alive); - is_alive = false; } bool PasswordForm::IsPossibleChangePasswordForm() const {
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h index a883bd9..66c58e4 100644 --- a/components/autofill/core/common/password_form.h +++ b/components/autofill/core/common/password_form.h
@@ -259,9 +259,6 @@ // If true, this form was parsed using Autofill predictions. bool was_parsed_using_autofill_predictions; - // TODO(vabr): Remove |is_alive| once http://crbug.com/486931 is fixed. - bool is_alive; // Set on construction, reset on destruction. - // If true, this match was found using public suffix matching. bool is_public_suffix_match;
diff --git a/components/autofill/ios/browser/autofill_driver_ios.h b/components/autofill/ios/browser/autofill_driver_ios.h index 7c665f56..e89c9e6 100644 --- a/components/autofill/ios/browser/autofill_driver_ios.h +++ b/components/autofill/ios/browser/autofill_driver_ios.h
@@ -58,6 +58,8 @@ void RendererShouldPreviewFieldWithValue( const base::string16& value) override; void PopupHidden() override; + gfx::RectF TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) override; private: AutofillDriverIOS(
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm index 1f32dddc..49a24f0f 100644 --- a/components/autofill/ios/browser/autofill_driver_ios.mm +++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -8,6 +8,7 @@ #include "ios/web/public/browser_state.h" #include "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_thread.h" +#include "ui/gfx/geometry/rect_f.h" DEFINE_WEB_STATE_USER_DATA_KEY(autofill::AutofillDriverIOS); @@ -98,4 +99,9 @@ void AutofillDriverIOS::PopupHidden() { } +gfx::RectF AutofillDriverIOS::TransformBoundingBoxToViewportCoordinates( + const gfx::RectF& bounding_box) { + return bounding_box; +} + } // namespace autofill
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 95a8118b..ab7c93c 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -758,6 +758,7 @@ ], 'tracing_unittest_sources': [ 'tracing/graphics_memory_dump_provider_android_unittest.cc', + 'tracing/process_metrics_memory_dump_provider_unittest.cc', 'tracing/trace_config_file_unittest.cc', ], 'translate_unittest_sources': [
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java index 0ede759..63365334 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -41,21 +41,6 @@ * then {@link #build} is called to create the {@code CronetEngine}. */ public static class Builder { - /** - * A class which provides a method for loading the cronet native library. Apps needing to - * implement custom library loading logic can inherit from this class and pass an instance - * to {@link CronetEngine.Builder#setLibraryLoader}. For example, this might be required - * to work around {@code UnsatisfiedLinkError}s caused by flaky installation on certain - * older devices. - */ - public abstract static class LibraryLoader { - /** - * Loads the native library. - * @param libName name of the library to load - */ - public abstract void loadLibrary(String libName); - } - // A hint that a host supports QUIC. static class QuicHint { // The host. @@ -101,7 +86,6 @@ private String mUserAgent; private String mStoragePath; private boolean mLegacyModeEnabled; - private LibraryLoader mLibraryLoader; private String mLibraryName; private boolean mQuicEnabled; private boolean mHttp2Enabled; @@ -203,22 +187,8 @@ return this; } - /** - * Sets a {@link LibraryLoader} to be used to load the native library. - * If not set, the library will be loaded using {@link System#loadLibrary}. - * @return the builder to facilitate chaining. - */ - public Builder setLibraryLoader(LibraryLoader loader) { - mLibraryLoader = loader; - return this; - } - - void loadLibrary() { - if (mLibraryLoader == null) { - System.loadLibrary(mLibraryName); - } else { - mLibraryLoader.loadLibrary(mLibraryName); - } + String libraryName() { + return mLibraryName; } /**
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java index e5db0b42..e51334e 100644 --- a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java +++ b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
@@ -32,7 +32,7 @@ if (sInitTaskPosted) { return; } - builder.loadLibrary(); + System.loadLibrary(builder.libraryName()); if (!Version.CRONET_VERSION.equals(nativeGetCronetVersion())) { throw new RuntimeException(String.format( "Expected Cronet version number %s, " @@ -74,7 +74,7 @@ nativeCronetInitOnMainThread(); } - // Native methods are implemented in cronet_library_loader.cc. + // Native methods are implemented in cronet_loader.cc. private static native void nativeCronetInitOnMainThread(); private static native String nativeGetCronetVersion(); }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java index 195eafcb..ce07d6b 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -960,35 +960,4 @@ // Verifies that CronetEngine.Builder config from testCronetEngineBuilderConfig() is properly // translated to a native UrlRequestContextConfig. private static native void nativeVerifyUrlRequestContextConfig(long config, String storagePath); - - private static class TestBadLibraryLoader extends CronetEngine.Builder.LibraryLoader { - private boolean mWasCalled = false; - - public void loadLibrary(String libName) { - // Report that this method was called, but don't load the library - mWasCalled = true; - } - - boolean wasCalled() { - return mWasCalled; - } - } - - @SmallTest - @Feature({"Cronet"}) - public void testSkipLibraryLoading() throws Exception { - CronetEngine.Builder builder = new CronetEngine.Builder(getContext()); - TestBadLibraryLoader loader = new TestBadLibraryLoader(); - builder.setLibraryLoader(loader).setLibraryName("cronet_tests"); - try { - // ensureInitialized() calls native code to check the version right after library load - // and will error with the message below if library loading was skipped - CronetLibraryLoader.ensureInitialized(getContext(), builder); - fail("Native library should not be loaded"); - } catch (UnsatisfiedLinkError e) { - assertTrue(e.getMessage().contains( - "No implementation found for java.lang.String org.chromium.net")); - assertTrue(loader.wasCalled()); - } - } }
diff --git a/components/html_viewer/html_frame.cc b/components/html_viewer/html_frame.cc index 4ee31a77..9cd0255 100644 --- a/components/html_viewer/html_frame.cc +++ b/components/html_viewer/html_frame.cc
@@ -316,7 +316,8 @@ blink::WebMediaPlayerClient* client, blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, blink::WebContentDecryptionModule* initial_cdm, - const blink::WebString& sink_id) { + const blink::WebString& sink_id, + blink::WebMediaSession* media_session) { return global_state()->media_factory()->CreateMediaPlayer( frame, url, client, encrypted_client, initial_cdm, GetApp()->shell()); }
diff --git a/components/html_viewer/html_frame.h b/components/html_viewer/html_frame.h index b9c0137e..1d7e7c3 100644 --- a/components/html_viewer/html_frame.h +++ b/components/html_viewer/html_frame.h
@@ -167,7 +167,8 @@ blink::WebMediaPlayerClient* client, blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, blink::WebContentDecryptionModule* initial_cdm, - const blink::WebString& sink_id) override; + const blink::WebString& sink_id, + blink::WebMediaSession* media_session) override; blink::WebFrame* createChildFrame( blink::WebLocalFrame* parent, blink::WebTreeScopeType scope,
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index e1fee32d..846cca42 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -418,108 +418,50 @@ } } logins_result.erase(begin_blacklisted, logins_result.end()); + if (logins_result.empty()) + return; // Now compute scores for the remaining credentials in |login_result|. std::vector<uint32_t> credential_scores; credential_scores.reserve(logins_result.size()); uint32_t best_score = 0; + std::map<base::string16, uint32_t> best_scores; for (const PasswordForm* login : logins_result) { uint32_t current_score = ScoreResult(*login); - if (current_score > best_score) - best_score = current_score; + best_score = std::max(best_score, current_score); + best_scores[login->username_value] = + std::max(best_scores[login->username_value], current_score); credential_scores.push_back(current_score); } - if (best_score == 0) { - if (logger) { - logger->LogNumber(Logger::STRING_BEST_SCORE, - static_cast<size_t>(best_score)); - } - return; - } - - // Start the |best_matches_| with the best-scoring normal credentials and save - // the worse-scoring "protected" ones for later. - ScopedVector<PasswordForm> protected_credentials; + // Fill |best_matches_| with the best-scoring credentials for each username. for (size_t i = 0; i < logins_result.size(); ++i) { // Take ownership of the PasswordForm from the ScopedVector. scoped_ptr<PasswordForm> login(logins_result[i]); logins_result[i] = nullptr; DCHECK(!login->blacklisted_by_user); + const base::string16& username = login->username_value; - if (credential_scores[i] < best_score) { - // Empty path matches are most commonly imports from Firefox, and - // generally useful to autofill. Blacklisted entries are only meaningful - // in the absence of non-blacklisted entries, in which case they need no - // protection to become |best_matches_|. TODO(timsteele): Bug 1269400. We - // probably should do something more elegant for any shorter-path match - // instead of explicitly handling empty path matches. - bool is_credential_protected = - observed_form_.scheme == PasswordForm::SCHEME_HTML && - base::StartsWith("/", login->origin.path(), - base::CompareCase::SENSITIVE) && - credential_scores[i] > 0; - // Passwords generated on a signup form must show on a login form even if - // there are better-matching saved credentials. TODO(gcasto): We don't - // want to cut credentials that were saved on signup forms even if they - // weren't generated, but currently it's hard to distinguish between those - // forms and two different login forms on the same domain. Filed - // http://crbug.com/294468 to look into this. - is_credential_protected |= login->type == PasswordForm::TYPE_GENERATED; - - // Websites that participate in affiliation-based matching will normally - // have a single authentication system per domain, therefore affiliation - // based matches are desired to be offered on any login form on the site. - // However, for Android credentials, most meta-data attributes are empty, - // so they will have a very low score, hence need to be protected against - // the high-scoring logins saved from the website. - is_credential_protected |= IsValidAndroidFacetURI(login->signon_realm); - - if (is_credential_protected) - protected_credentials.push_back(std::move(login)); - else - not_best_matches_.push_back(std::move(login)); + if (credential_scores[i] < best_scores[username]) { + not_best_matches_.push_back(std::move(login)); continue; } + if (!preferred_match_ && credential_scores[i] == best_score) + preferred_match_ = login.get(); + // If there is another best-score match for the same username then leave it // and add the current form to |not_best_matches_|. - const base::string16& username = login->username_value; auto best_match_username = best_matches_.find(username); if (best_match_username == best_matches_.end()) { - if (login->preferred) - preferred_match_ = login.get(); best_matches_.insert(std::make_pair(username, std::move(login))); } else { not_best_matches_.push_back(std::move(login)); } } - // Add the protected results if we don't already have a result with the same - // username. - for (ScopedVector<PasswordForm>::iterator it = protected_credentials.begin(); - it != protected_credentials.end(); ++it) { - // Take ownership of the PasswordForm from the ScopedVector. - scoped_ptr<PasswordForm> protege(*it); - *it = nullptr; - const base::string16& username = protege->username_value; - if (best_matches_.find(username) == best_matches_.end()) - best_matches_.insert(std::make_pair(username, std::move(protege))); - else - not_best_matches_.push_back(std::move(protege)); - } - UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown", logins_result_size - best_matches_.size()); - - if (!best_matches_.empty()) { - // It is possible we have at least one match but have no preferred_match_, - // because a user may have chosen to 'Forget' the preferred match. So we - // just pick the first one and whichever the user selects for submit will - // be saved as preferred. - if (!preferred_match_) - preferred_match_ = best_matches_.begin()->second.get(); - } } void PasswordFormManager::ProcessFrame( @@ -686,7 +628,7 @@ PasswordFormMap::const_iterator iter; for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) { if (iter->second->username_value != pending_credentials_.username_value && - iter->second->preferred) { + iter->second->preferred && !iter->second->is_public_suffix_match) { // This wasn't the selected login but it used to be preferred. iter->second->preferred = false; if (user_action_ == kUserActionNone) @@ -1146,8 +1088,12 @@ uint32_t score = 0u; if (!candidate.is_public_suffix_match) { - score += 1u << 7; + score += 1u << 8; } + + if (candidate.preferred) + score += 1u << 7; + if (candidate.origin == observed_form_.origin) { // This check is here for the most common case which // is we have a single match in the db for the given host,
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 56af53e..1d94403 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -1116,18 +1116,32 @@ form_manager()->OnGetPasswordStoreResults(std::move(simulated_results)); } -TEST_F(PasswordFormManagerTest, TestForceInclusionOfGeneratedPasswords_Match) { - // Simulate having two matches for this origin, one of which was from a form - // with different HTML tags for elements. Because of scoring differences, - // only the first form will be sent to Autofill(). - EXPECT_CALL(*client()->mock_driver(), AllowPasswordGenerationForForm(_)); - +TEST_F(PasswordFormManagerTest, TestBestCredentialsByEachUsernameAreIncluded) { + // Simulate having several matches, with 3 different usernames. Some of the + // matches are PSL matches. One match for each username should be chosen. ScopedVector<PasswordForm> simulated_results; - simulated_results.push_back(CreateSavedMatch(false)); - simulated_results.push_back(CreateSavedMatch(false)); - simulated_results[1]->username_value = ASCIIToUTF16("other@gmail.com"); + // Add a best scoring match. It should be in |best_matches| and chosen as a + // prefferred match. + simulated_results.push_back(new PasswordForm(*saved_match())); + // Add a match saved on another form, it has lower score. It should not be in + // |best_matches|. + simulated_results.push_back(new PasswordForm(*saved_match())); simulated_results[1]->password_element = ASCIIToUTF16("signup_password"); simulated_results[1]->username_element = ASCIIToUTF16("signup_username"); + // Add a match saved on another form with a different username. It should be + // in |best_matches|. + simulated_results.push_back(new PasswordForm(*saved_match())); + auto username1 = simulated_results[0]->username_value + ASCIIToUTF16("1"); + simulated_results[2]->username_value = username1; + simulated_results[2]->password_element = ASCIIToUTF16("signup_password"); + simulated_results[2]->username_element = ASCIIToUTF16("signup_username"); + // Add a PSL match, it should not be in |best_matches|. + simulated_results.push_back(new PasswordForm(*psl_saved_match())); + // Add a PSL match with a different username. It should be in |best_matches|. + simulated_results.push_back(new PasswordForm(*psl_saved_match())); + auto username2 = simulated_results[0]->username_value + ASCIIToUTF16("2"); + simulated_results[4]->username_value = username2; + form_manager()->SimulateFetchMatchingLoginsFromPasswordStore(); autofill::PasswordFormFillData fill_data; @@ -1135,8 +1149,18 @@ .WillOnce(SaveArg<0>(&fill_data)); form_manager()->OnGetPasswordStoreResults(std::move(simulated_results)); - EXPECT_EQ(1u, form_manager()->best_matches().size()); - EXPECT_TRUE(fill_data.additional_logins.empty()); + const autofill::PasswordFormMap& best_matches = + form_manager()->best_matches(); + EXPECT_EQ(3u, best_matches.size()); + EXPECT_NE(best_matches.end(), + best_matches.find(saved_match()->username_value)); + EXPECT_EQ(*saved_match(), + *best_matches.find(saved_match()->username_value)->second); + EXPECT_NE(best_matches.end(), best_matches.find(username1)); + EXPECT_NE(best_matches.end(), best_matches.find(username2)); + + EXPECT_EQ(*saved_match(), *form_manager()->preferred_match()); + EXPECT_EQ(2u, fill_data.additional_logins.size()); } TEST_F(PasswordFormManagerTest,
diff --git a/components/policy/core/common/cloud/enterprise_metrics.cc b/components/policy/core/common/cloud/enterprise_metrics.cc index e0cedf2c..a1b0f3f 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.cc +++ b/components/policy/core/common/cloud/enterprise_metrics.cc
@@ -13,6 +13,5 @@ const char kMetricDevicePolicyRefresh[] = "Enterprise.DevicePolicyRefresh"; const char kMetricDevicePolicyInvalidations[] = "Enterprise.DevicePolicyInvalidations"; -const char kMetricSystemLogPII[] = "Enterprise.SystemLogPIILeak"; } // namespace policy
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h index ae51e2b7..179feaf 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.h +++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -265,24 +265,6 @@ POLICY_INVALIDATION_TYPE_SIZE // Must be the last. }; -// Types of sensitive data that is removed from system logs to upload. -// This enum is used to define the buckets for an enumerated UMA histogram. -// Hence, -// (a) existing enumerated constants should never be deleted or reordered, and -// (b) new constants should only be appended at the end of the enumeration. -enum SystemLogPIIType { - // Found email address in system logs to upload. - SYSTEM_LOG_PII_TYPE_EMAIL_ADDRESS = 0, - // Found IP address in system logs to upload. - SYSTEM_LOG_PII_TYPE_IP_ADDRESS = 1, - // Found Web URL in system logs to upload. - SYSTEM_LOG_PII_TYPE_WEB_URL = 2, - // Found SSID in system logs to upload. - SYSTEM_LOG_PII_TYPE_SSID = 3, - - SYSTEM_LOG_PII_TYPE_SIZE // Must be the last. -}; - // Names for the UMA counters. They are shared from here since the events // from the same enum above can be triggered in different files, and must use // the same UMA histogram name. @@ -292,7 +274,6 @@ POLICY_EXPORT extern const char kMetricUserPolicyInvalidations[]; POLICY_EXPORT extern const char kMetricDevicePolicyRefresh[]; POLICY_EXPORT extern const char kMetricDevicePolicyInvalidations[]; -POLICY_EXPORT extern const char kMetricSystemLogPII[]; } // namespace policy
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc index 7334f74..2ea3db6a 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -632,16 +632,12 @@ bool loading_tasks_seem_expensive = false; bool timer_tasks_seem_expensive = false; - // Only deem tasks to be exensive (which may cause them to be preemptively - // blocked) if we are expecting frames. - if (!MainThreadOnly().begin_frame_not_expected_soon) { - loading_tasks_seem_expensive = - MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > - longest_jank_free_task_duration; - timer_tasks_seem_expensive = - MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > - longest_jank_free_task_duration; - } + loading_tasks_seem_expensive = + MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > + longest_jank_free_task_duration; + timer_tasks_seem_expensive = + MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > + longest_jank_free_task_duration; MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive; MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc index cc6616b..0c73012 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -2282,7 +2282,7 @@ } TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskNotBlocked_IfBeginMainFrameNotExpectedSoon) { + ExpensiveTimerTaskBlocked_EvenIfBeginMainFrameNotExpectedSoon) { std::vector<std::string> run_order; scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); @@ -2297,10 +2297,9 @@ EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); EXPECT_TRUE(HaveSeenABeginMainframe()); EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("D1"))); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); } TEST_F(RendererSchedulerImplTest,
diff --git a/components/tracing.gyp b/components/tracing.gyp index d0d7677..9466a1c8 100644 --- a/components/tracing.gyp +++ b/components/tracing.gyp
@@ -32,6 +32,8 @@ 'tracing/child_trace_message_filter.h', 'tracing/graphics_memory_dump_provider_android.cc', 'tracing/graphics_memory_dump_provider_android.h', + 'tracing/process_metrics_memory_dump_provider.cc', + 'tracing/process_metrics_memory_dump_provider.h', 'tracing/trace_config_file.cc', 'tracing/trace_config_file.h', 'tracing/trace_to_console.cc', @@ -42,6 +44,13 @@ 'tracing/tracing_switches.cc', 'tracing/tracing_switches.h', ], + 'target_conditions': [ + ['>(nacl_untrusted_build)==1', { + 'sources!': [ + 'tracing/process_metrics_memory_dump_provider.cc', + ], + }], + ] }, ], }
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn index 0111de9..927aeb67 100644 --- a/components/tracing/BUILD.gn +++ b/components/tracing/BUILD.gn
@@ -10,6 +10,8 @@ "child_trace_message_filter.h", "graphics_memory_dump_provider_android.cc", "graphics_memory_dump_provider_android.h", + "process_metrics_memory_dump_provider.cc", + "process_metrics_memory_dump_provider.h", "tracing_export.h", "tracing_messages.cc", "tracing_messages.h", @@ -21,6 +23,10 @@ "//base", "//ipc", ] + + if (is_nacl) { + sources -= [ "process_metrics_memory_dump_provider.cc" ] + } } component("startup_tracing") { @@ -46,6 +52,7 @@ sources = [ "graphics_memory_dump_provider_android_unittest.cc", + "process_metrics_memory_dump_provider_unittest.cc", ] deps = [
diff --git a/components/tracing/child_memory_dump_manager_delegate_impl.cc b/components/tracing/child_memory_dump_manager_delegate_impl.cc index 05c26627..ced940b 100644 --- a/components/tracing/child_memory_dump_manager_delegate_impl.cc +++ b/components/tracing/child_memory_dump_manager_delegate_impl.cc
@@ -5,7 +5,9 @@ #include "components/tracing/child_memory_dump_manager_delegate_impl.h" #include "base/single_thread_task_runner.h" +#include "build/build_config.h" #include "components/tracing/child_trace_message_filter.h" +#include "components/tracing/process_metrics_memory_dump_provider.h" namespace tracing { @@ -49,6 +51,13 @@ if (ctmf) { base::trace_event::MemoryDumpManager::GetInstance()->Initialize( this /* delegate */, false /* is_coordinator */); + +#if !defined(OS_LINUX) && !defined(OS_NACL) + // On linux the browser process takes care of dumping process metrics. + // The child process is not allowed to do so due to BPF sandbox. + tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( + base::kNullProcessId); +#endif } }
diff --git a/components/tracing/process_metrics_memory_dump_provider.cc b/components/tracing/process_metrics_memory_dump_provider.cc new file mode 100644 index 0000000..e73ea78 --- /dev/null +++ b/components/tracing/process_metrics_memory_dump_provider.cc
@@ -0,0 +1,305 @@ +// 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/tracing/process_metrics_memory_dump_provider.h" + +#include <fcntl.h> +#include <stdint.h> + +#include <map> + +#include "base/files/file_util.h" +#include "base/files/scoped_file.h" +#include "base/format_macros.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/process/process_metrics.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/process_memory_dump.h" +#include "base/trace_event/process_memory_maps.h" +#include "base/trace_event/process_memory_totals.h" +#include "build/build_config.h" + +namespace tracing { + +namespace { + +base::LazyInstance< + std::map<base::ProcessId, scoped_ptr<ProcessMetricsMemoryDumpProvider>>>:: + Leaky g_dump_providers_map = LAZY_INSTANCE_INITIALIZER; + +#if defined(OS_LINUX) || defined(OS_ANDROID) +const char kClearPeakRssCommand[] = "5"; + +const uint32_t kMaxLineSize = 4096; + +bool ParseSmapsHeader(const char* header_line, + base::trace_event::ProcessMemoryMaps::VMRegion* region) { + // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n" + bool res = true; // Whether this region should be appended or skipped. + uint64_t end_addr = 0; + char protection_flags[5] = {0}; + char mapped_file[kMaxLineSize]; + + if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n", + ®ion->start_address, &end_addr, protection_flags, + mapped_file) != 4) + return false; + + if (end_addr > region->start_address) { + region->size_in_bytes = end_addr - region->start_address; + } else { + // This is not just paranoia, it can actually happen (See crbug.com/461237). + region->size_in_bytes = 0; + res = false; + } + + region->protection_flags = 0; + if (protection_flags[0] == 'r') { + region->protection_flags |= + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead; + } + if (protection_flags[1] == 'w') { + region->protection_flags |= + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite; + } + if (protection_flags[2] == 'x') { + region->protection_flags |= + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec; + } + + region->mapped_file = mapped_file; + base::TrimWhitespaceASCII(region->mapped_file, base::TRIM_ALL, + ®ion->mapped_file); + + return res; +} + +uint64_t ReadCounterBytes(char* counter_line) { + uint64_t counter_value = 0; + int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value); + return res == 1 ? counter_value * 1024 : 0; +} + +uint32_t ParseSmapsCounter( + char* counter_line, + base::trace_event::ProcessMemoryMaps::VMRegion* region) { + // A smaps counter lines looks as follows: "RSS: 0 Kb\n" + uint32_t res = 1; + char counter_name[20]; + int did_read = sscanf(counter_line, "%19[^\n ]", counter_name); + if (did_read != 1) + return 0; + + if (strcmp(counter_name, "Pss:") == 0) { + region->byte_stats_proportional_resident = ReadCounterBytes(counter_line); + } else if (strcmp(counter_name, "Private_Dirty:") == 0) { + region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line); + } else if (strcmp(counter_name, "Private_Clean:") == 0) { + region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line); + } else if (strcmp(counter_name, "Shared_Dirty:") == 0) { + region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line); + } else if (strcmp(counter_name, "Shared_Clean:") == 0) { + region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line); + } else if (strcmp(counter_name, "Swap:") == 0) { + region->byte_stats_swapped = ReadCounterBytes(counter_line); + } else { + res = 0; + } + + return res; +} + +uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file, + base::trace_event::ProcessMemoryMaps* pmm) { + if (!smaps_file) + return 0; + + fseek(smaps_file, 0, SEEK_SET); + + char line[kMaxLineSize]; + const uint32_t kNumExpectedCountersPerRegion = 6; + uint32_t counters_parsed_for_current_region = 0; + uint32_t num_valid_regions = 0; + base::trace_event::ProcessMemoryMaps::VMRegion region; + bool should_add_current_region = false; + for (;;) { + line[0] = '\0'; + if (fgets(line, kMaxLineSize, smaps_file) == nullptr || !strlen(line)) + break; + if (isxdigit(line[0]) && !isupper(line[0])) { + region = base::trace_event::ProcessMemoryMaps::VMRegion(); + counters_parsed_for_current_region = 0; + should_add_current_region = ParseSmapsHeader(line, ®ion); + } else { + counters_parsed_for_current_region += ParseSmapsCounter(line, ®ion); + DCHECK_LE(counters_parsed_for_current_region, + kNumExpectedCountersPerRegion); + if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) { + if (should_add_current_region) { + pmm->AddVMRegion(region); + ++num_valid_regions; + should_add_current_region = false; + } + } + } + } + return num_valid_regions; +} +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + +scoped_ptr<base::ProcessMetrics> CreateProcessMetrics(base::ProcessId process) { + if (process == base::kNullProcessId) + return make_scoped_ptr(base::ProcessMetrics::CreateCurrentProcessMetrics()); +#if defined(OS_LINUX) || defined(OS_ANDROID) + // Just pass ProcessId instead of handle since they are the same in linux and + // android. + return make_scoped_ptr(base::ProcessMetrics::CreateProcessMetrics(process)); +#else + // Creating process metrics for child processes in mac or windows requires + // additional information like ProcessHandle or port provider. This is a non + // needed use case. + NOTREACHED(); + return scoped_ptr<base::ProcessMetrics>(); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) +} + +} // namespace + +// static +uint64_t ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0; + +#if defined(OS_LINUX) || defined(OS_ANDROID) + +// static +FILE* ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = nullptr; + +bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + uint32_t res = 0; + if (proc_smaps_for_testing) { + res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps()); + } else { + std::string file_name = "/proc/" + (process_ == base::kNullProcessId + ? "self" + : base::IntToString(process_)) + + "/smaps"; + base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r")); + res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps()); + } + + if (res) + pmd->set_has_process_mmaps(); + return res; +} +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + +// static +void ProcessMetricsMemoryDumpProvider::RegisterForProcess( + base::ProcessId process) { + scoped_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider( + new ProcessMetricsMemoryDumpProvider(process)); + base::trace_event::MemoryDumpProvider::Options options(process); + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options); + bool did_insert = + g_dump_providers_map.Get() + .insert(std::make_pair(process, std::move(metrics_provider))) + .second; + if (!did_insert) { + DLOG(ERROR) << "ProcessMetricsMemoryDumpProvider already registered for " + << (process == base::kNullProcessId + ? "current process" + : "process id " + base::IntToString(process)); + } +} + +// static +void ProcessMetricsMemoryDumpProvider::UnregisterForProcess( + base::ProcessId process) { + auto iter = g_dump_providers_map.Get().find(process); + if (iter == g_dump_providers_map.Get().end()) { + return; + } + base::trace_event::MemoryDumpManager::GetInstance() + ->UnregisterAndDeleteDumpProviderSoon(std::move(iter->second)); + g_dump_providers_map.Get().erase(iter); +} + +ProcessMetricsMemoryDumpProvider::ProcessMetricsMemoryDumpProvider( + base::ProcessId process) + : process_(process), + process_metrics_(CreateProcessMetrics(process)), + is_rss_peak_resettable_(true) {} + +ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {} + +// Called at trace dump point time. Creates a snapshot of the memory maps for +// the current process. +bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + bool res = DumpProcessTotals(args, pmd); + +#if defined(OS_LINUX) || defined(OS_ANDROID) + if (args.level_of_detail == + base::trace_event::MemoryDumpLevelOfDetail::DETAILED) + res &= DumpProcessMemoryMaps(args, pmd); +#endif + return res; +} + +bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + const uint64_t rss_bytes = rss_bytes_for_testing + ? rss_bytes_for_testing + : process_metrics_->GetWorkingSetSize(); + + // rss_bytes will be 0 if the process ended while dumping. + if (!rss_bytes) + return false; + + uint64_t peak_rss_bytes = 0; + +#if !defined(OS_IOS) + peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize(); +#if defined(OS_LINUX) || defined(OS_ANDROID) + if (is_rss_peak_resettable_) { + std::string clear_refs_file = + "/proc/" + + (process_ == base::kNullProcessId ? "self" + : base::IntToString(process_)) + + "/clear_refs"; + int clear_refs_fd = open(clear_refs_file.c_str(), O_WRONLY); + if (clear_refs_fd > 0 && + base::WriteFileDescriptor(clear_refs_fd, kClearPeakRssCommand, + sizeof(kClearPeakRssCommand))) { + pmd->process_totals()->set_is_peak_rss_resetable(true); + } else { + is_rss_peak_resettable_ = false; + } + close(clear_refs_fd); + } +#elif defined(MACOSX) + size_t private_bytes; + bool res = process_metrics_->GetMemoryBytes(&private_bytes, + nullptr /* shared_bytes */); + if (res) + pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) +#endif // !defined(OS_IOS) + + pmd->process_totals()->set_resident_set_bytes(rss_bytes); + pmd->set_has_process_totals(); + pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes); + + // Returns true even if other metrics failed, since rss is reported. + return true; +} + +} // namespace tracing
diff --git a/components/tracing/process_metrics_memory_dump_provider.h b/components/tracing/process_metrics_memory_dump_provider.h new file mode 100644 index 0000000..b002d10 --- /dev/null +++ b/components/tracing/process_metrics_memory_dump_provider.h
@@ -0,0 +1,67 @@ +// 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_TRACING_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_ +#define COMPONENTS_TRACING_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_ + +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/process/process_handle.h" +#include "base/trace_event/memory_dump_provider.h" +#include "build/build_config.h" +#include "components/tracing/tracing_export.h" + +namespace base { +class ProcessMetrics; +} + +namespace tracing { + +// Dump provider which collects process-wide memory stats. +class TRACING_EXPORT ProcessMetricsMemoryDumpProvider + : public base::trace_event::MemoryDumpProvider { + public: + // Pass base::kNullProcessId to register for current process. + static void RegisterForProcess(base::ProcessId process); + static void UnregisterForProcess(base::ProcessId process); + + ~ProcessMetricsMemoryDumpProvider() override; + + // MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + + private: + FRIEND_TEST_ALL_PREFIXES(ProcessMetricsMemoryDumpProviderTest, + ParseProcSmaps); + FRIEND_TEST_ALL_PREFIXES(ProcessMetricsMemoryDumpProviderTest, DumpRSS); + + ProcessMetricsMemoryDumpProvider(base::ProcessId process); + + bool DumpProcessTotals(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd); + bool DumpProcessMemoryMaps(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd); + + static uint64_t rss_bytes_for_testing; + +#if defined(OS_LINUX) || defined(OS_ANDROID) + static FILE* proc_smaps_for_testing; +#endif + + base::ProcessId process_; + scoped_ptr<base::ProcessMetrics> process_metrics_; + + // The peak may not be resettable on all the processes if the linux kernel is + // older than http://bit.ly/reset_rss or only on child processes if yama LSM + // sandbox is enabled. + bool is_rss_peak_resettable_; + + DISALLOW_COPY_AND_ASSIGN(ProcessMetricsMemoryDumpProvider); +}; + +} // namespace tracing + +#endif // COMPONENTS_TRACING_PROCESS_MEMORY_METRICS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/components/tracing/process_metrics_memory_dump_provider_unittest.cc similarity index 68% rename from base/trace_event/process_memory_maps_dump_provider_unittest.cc rename to components/tracing/process_metrics_memory_dump_provider_unittest.cc index 624f96f..62e8fd6 100644 --- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc +++ b/components/tracing/process_metrics_memory_dump_provider_unittest.cc
@@ -2,19 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/trace_event/process_memory_maps_dump_provider.h" +#include "components/tracing/process_metrics_memory_dump_provider.h" #include <stdint.h> #include "base/files/file_util.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/process_memory_maps.h" +#include "base/trace_event/process_memory_totals.h" #include "base/trace_event/trace_event_argument.h" #include "testing/gtest/include/gtest/gtest.h" -namespace base { -namespace trace_event { +namespace tracing { +#if defined(OS_LINUX) || defined(OS_ANDROID) namespace { const char kTestSmaps1[] = "00400000-004be000 r-xp 00000000 fc:01 1234 /file/1\n" @@ -105,8 +106,8 @@ "VmFlags: rd wr mr mw me ac sd\n"; void CreateAndSetSmapsFileForTesting(const char* smaps_string, - ScopedFILE& file) { - FilePath temp_path; + base::ScopedFILE& file) { + base::FilePath temp_path; FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path); file.reset(temp_file); ASSERT_TRUE(temp_file); @@ -116,28 +117,69 @@ } } // namespace +#endif // defined(OS_LINUX) || defined(OS_ANDROID) -TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) { - const uint32_t kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead; - const uint32_t kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite; - const uint32_t kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec; - const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; +TEST(ProcessMetricsMemoryDumpProviderTest, DumpRSS) { + const base::trace_event::MemoryDumpArgs high_detail_args = { + base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; + scoped_ptr<ProcessMetricsMemoryDumpProvider> pmtdp( + new ProcessMetricsMemoryDumpProvider(base::kNullProcessId)); + scoped_ptr<base::trace_event::ProcessMemoryDump> pmd_before( + new base::trace_event::ProcessMemoryDump(nullptr)); + scoped_ptr<base::trace_event::ProcessMemoryDump> pmd_after( + new base::trace_event::ProcessMemoryDump(nullptr)); - auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance(); + ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 1024; + pmtdp->OnMemoryDump(high_detail_args, pmd_before.get()); + + // Pretend that the RSS of the process increased of +1M. + const size_t kAllocSize = 1048576; + ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing += kAllocSize; + + pmtdp->OnMemoryDump(high_detail_args, pmd_after.get()); + + ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0; + + ASSERT_TRUE(pmd_before->has_process_totals()); + ASSERT_TRUE(pmd_after->has_process_totals()); + + const uint64_t rss_before = + pmd_before->process_totals()->resident_set_bytes(); + const uint64_t rss_after = pmd_after->process_totals()->resident_set_bytes(); + + EXPECT_NE(0U, rss_before); + EXPECT_NE(0U, rss_after); + + EXPECT_EQ(rss_after - rss_before, kAllocSize); +} + +#if defined(OS_LINUX) || defined(OS_ANDROID) +TEST(ProcessMetricsMemoryDumpProviderTest, ParseProcSmaps) { + const uint32_t kProtR = + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead; + const uint32_t kProtW = + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite; + const uint32_t kProtX = + base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec; + const base::trace_event::MemoryDumpArgs dump_args = { + base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; + + scoped_ptr<ProcessMetricsMemoryDumpProvider> pmmdp( + new ProcessMetricsMemoryDumpProvider(base::kNullProcessId)); // Emulate an empty /proc/self/smaps. - ProcessMemoryDump pmd_invalid(nullptr /* session_state */); - ScopedFILE empty_file(OpenFile(FilePath("/dev/null"), "r")); + base::trace_event::ProcessMemoryDump pmd_invalid(nullptr /* session_state */); + base::ScopedFILE empty_file(OpenFile(base::FilePath("/dev/null"), "r")); ASSERT_TRUE(empty_file.get()); - ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = empty_file.get(); + ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = empty_file.get(); pmmdp->OnMemoryDump(dump_args, &pmd_invalid); ASSERT_FALSE(pmd_invalid.has_process_mmaps()); // Parse the 1st smaps file. - ProcessMemoryDump pmd_1(nullptr /* session_state */); - ScopedFILE temp_file1; + base::trace_event::ProcessMemoryDump pmd_1(nullptr /* session_state */); + base::ScopedFILE temp_file1; CreateAndSetSmapsFileForTesting(kTestSmaps1, temp_file1); - ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file1.get(); + ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file1.get(); pmmdp->OnMemoryDump(dump_args, &pmd_1); ASSERT_TRUE(pmd_1.has_process_mmaps()); const auto& regions_1 = pmd_1.process_mmaps()->vm_regions(); @@ -166,10 +208,10 @@ EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped); // Parse the 2nd smaps file. - ProcessMemoryDump pmd_2(nullptr /* session_state */); - ScopedFILE temp_file2; + base::trace_event::ProcessMemoryDump pmd_2(nullptr /* session_state */); + base::ScopedFILE temp_file2; CreateAndSetSmapsFileForTesting(kTestSmaps2, temp_file2); - ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file2.get(); + ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file2.get(); pmmdp->OnMemoryDump(dump_args, &pmd_2); ASSERT_TRUE(pmd_2.has_process_mmaps()); const auto& regions_2 = pmd_2.process_mmaps()->vm_regions(); @@ -185,6 +227,6 @@ EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident); EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped); } +#endif // defined(OS_LINUX) || defined(OS_ANDROID) -} // namespace trace_event -} // namespace base +} // namespace tracing
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index e815e85..141eab8 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -32,6 +32,7 @@ #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "components/tracing/process_metrics_memory_dump_provider.h" #include "components/tracing/trace_config_file.h" #include "components/tracing/trace_to_console.h" #include "components/tracing/tracing_switches.h" @@ -696,6 +697,8 @@ // Enable memory-infra dump providers. InitSkiaEventTracer(); + tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( + base::kNullProcessId); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( HostSharedBitmapManager::current(), "HostSharedBitmapManager", nullptr); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc index 1d8b23c0..fef7ff7 100644 --- a/content/browser/frame_host/cross_process_frame_connector.cc +++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -172,15 +172,15 @@ root_view->UpdateCursor(cursor); } -void CrossProcessFrameConnector::TransformPointToRootCoordSpace( +gfx::Point CrossProcessFrameConnector::TransformPointToRootCoordSpace( const gfx::Point& point, - cc::SurfaceId surface_id, - gfx::Point* transformed_point) { + cc::SurfaceId surface_id) { + gfx::Point transformed_point = point; RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView(); - *transformed_point = point; if (root_view) root_view->TransformPointToLocalCoordSpace(point, surface_id, - transformed_point); + &transformed_point); + return transformed_point; } bool CrossProcessFrameConnector::HasFocus() {
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h index 6f31ec60..6ad56a21 100644 --- a/content/browser/frame_host/cross_process_frame_connector.h +++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -101,9 +101,8 @@ float device_scale_factor() const { return device_scale_factor_; } void GetScreenInfo(blink::WebScreenInfo* results); void UpdateCursor(const WebCursor& cursor); - void TransformPointToRootCoordSpace(const gfx::Point& point, - cc::SurfaceId surface_id, - gfx::Point* transformed_point); + gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point, + cc::SurfaceId surface_id); // Determines whether the root RenderWidgetHostView (and thus the current // page) has focus.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index b63e42f..4759476 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1327,9 +1327,9 @@ // It is necessary to transform the coordinates to account for nested // RenderWidgetHosts, such as with out-of-process iframes. gfx::Point original_point(validated_params.x, validated_params.y); - gfx::Point transformed_point = original_point; - static_cast<RenderWidgetHostViewBase*>(GetView()) - ->TransformPointToRootCoordSpace(original_point, &transformed_point); + gfx::Point transformed_point = + static_cast<RenderWidgetHostViewBase*>(GetView()) + ->TransformPointToRootCoordSpace(original_point); validated_params.x = transformed_point.x(); validated_params.y = transformed_point.y();
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index abd5d53..61c61a3 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -168,6 +168,7 @@ void InsertVisualStateCallback( const VisualStateCallback& callback) override; bool IsRenderFrameLive() override; + RenderWidgetHostView* GetView() override; #if defined(OS_ANDROID) void ActivateNearestFindResult(int request_id, float x, float y) override; void RequestFindMatchRects(int current_version) override; @@ -251,9 +252,6 @@ // pointer to the RenderViewHost (which inherits RenderWidgetHost). RenderWidgetHostImpl* GetRenderWidgetHost(); - // This returns the RenderWidgetHostView that can be used to control - // focus and visibility for this frame. - RenderWidgetHostView* GetView(); // This function is called when this is a swapped out RenderFrameHost that // lives in the same process as the parent frame. The
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 98119d15b..10a0681 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -381,15 +381,12 @@ host_->ForwardWheelEvent(event); } -void RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace( - const gfx::Point& point, - gfx::Point* transformed_point) { - *transformed_point = point; +gfx::Point RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace( + const gfx::Point& point) { if (!frame_connector_ || !use_surfaces_) - return; + return point; - frame_connector_->TransformPointToRootCoordSpace(point, surface_id_, - transformed_point); + return frame_connector_->TransformPointToRootCoordSpace(point, surface_id_); } #if defined(OS_MACOSX)
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h index 4bacd21f3..c77b216 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.h +++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -128,8 +128,7 @@ void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event) override; void ProcessMouseEvent(const blink::WebMouseEvent& event) override; void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override; - void TransformPointToRootCoordSpace(const gfx::Point& point, - gfx::Point* transformed_point) override; + gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point) override; #if defined(OS_MACOSX) // RenderWidgetHostView implementation.
diff --git a/content/browser/media/android/browser_media_session_manager.cc b/content/browser/media/android/browser_media_session_manager.cc index 146a60fe..a7e5fd5b 100644 --- a/content/browser/media/android/browser_media_session_manager.cc +++ b/content/browser/media/android/browser_media_session_manager.cc
@@ -6,6 +6,8 @@ #include "content/common/media/media_session_messages_android.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/common/media_metadata.h" namespace content { @@ -23,6 +25,27 @@ Send(new MediaSessionMsg_DidDeactivate(GetRoutingID(), request_id)); } +void BrowserMediaSessionManager::OnSetMetadata( + int session_id, + const MediaMetadata& insecure_metadata) { + // When receiving a MediaMetadata, the browser process can't trust that it is + // coming from a known and secure source. It must be processed accordingly. + MediaMetadata metadata; + metadata.title = + insecure_metadata.title.substr(0, MediaMetadata::kMaxIPCStringLength); + metadata.artist = + insecure_metadata.artist.substr(0, MediaMetadata::kMaxIPCStringLength); + metadata.album = + insecure_metadata.album.substr(0, MediaMetadata::kMaxIPCStringLength); + + if (metadata != insecure_metadata) { + render_frame_host_->GetProcess()->ShutdownForBadMessage(); + return; + } + + NOTIMPLEMENTED(); +} + int BrowserMediaSessionManager::GetRoutingID() const { return render_frame_host_->GetRoutingID(); }
diff --git a/content/browser/media/android/browser_media_session_manager.h b/content/browser/media/android/browser_media_session_manager.h index 3b07b295..b936ba0 100644 --- a/content/browser/media/android/browser_media_session_manager.h +++ b/content/browser/media/android/browser_media_session_manager.h
@@ -14,6 +14,7 @@ namespace content { class RenderFrameHost; +struct MediaMetadata; class BrowserMediaSessionManager { public: @@ -22,6 +23,7 @@ // Message handlers. void OnActivate(int session_id, int request_id); void OnDeactivate(int session_id, int request_id); + void OnSetMetadata(int session_id, const MediaMetadata& metadata); int GetRoutingID() const;
diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc index 1b48959..224a8f1 100644 --- a/content/browser/media/android/media_web_contents_observer_android.cc +++ b/content/browser/media/android/media_web_contents_observer_android.cc
@@ -96,7 +96,13 @@ if (OnMediaPlayerMessageReceived(msg, render_frame_host)) return true; - return OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host); + if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host)) + return true; + + if (OnMediaSessionMessageReceived(msg, render_frame_host)) + return true; + + return false; } bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived( @@ -143,12 +149,6 @@ GetMediaPlayerManager(render_frame_host), BrowserMediaPlayerManager::OnNotifyExternalSurface) #endif // defined(VIDEO_HOLE) - IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Activate, - GetMediaSessionManager(render_frame_host), - BrowserMediaSessionManager::OnActivate) - IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Deactivate, - GetMediaSessionManager(render_frame_host), - BrowserMediaSessionManager::OnDeactivate) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -166,6 +166,27 @@ return handled; } +bool MediaWebContentsObserverAndroid::OnMediaSessionMessageReceived( + const IPC::Message& msg, + RenderFrameHost* render_frame_host) { + bool handled = true; + + IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver, msg) + IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Activate, + GetMediaSessionManager(render_frame_host), + BrowserMediaSessionManager::OnActivate) + IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Deactivate, + GetMediaSessionManager(render_frame_host), + BrowserMediaSessionManager::OnDeactivate) + IPC_MESSAGE_FORWARD(MediaSessionHostMsg_SetMetadata, + GetMediaSessionManager(render_frame_host), + BrowserMediaSessionManager::OnSetMetadata) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + void MediaWebContentsObserverAndroid::OnSetCdm( RenderFrameHost* render_frame_host, int player_id,
diff --git a/content/browser/media/android/media_web_contents_observer_android.h b/content/browser/media/android/media_web_contents_observer_android.h index a95e161..5a6f481 100644 --- a/content/browser/media/android/media_web_contents_observer_android.h +++ b/content/browser/media/android/media_web_contents_observer_android.h
@@ -56,6 +56,9 @@ bool OnMediaPlayerSetCdmMessageReceived(const IPC::Message& message, RenderFrameHost* render_frame_host); + bool OnMediaSessionMessageReceived(const IPC::Message& message, + RenderFrameHost* render_frame_host); + void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id); // Map from RenderFrameHost* to BrowserMediaPlayerManager.
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index a2a0884..3bd1ffc 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -14,6 +14,7 @@ #include "content/common/content_switches_internal.h" #include "content/public/browser/render_widget_host_view_frame_subscriber.h" #include "ui/gfx/display.h" +#include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/screen.h" @@ -682,10 +683,15 @@ return 0; } -void RenderWidgetHostViewBase::TransformPointToRootCoordSpace( - const gfx::Point& point, - gfx::Point* transformed_point) { - *transformed_point = point; +gfx::Point RenderWidgetHostViewBase::TransformPointToRootCoordSpace( + const gfx::Point& point) { + return point; +} + +gfx::PointF RenderWidgetHostViewBase::TransformPointToRootCoordSpaceF( + const gfx::PointF& point) { + return gfx::PointF(TransformPointToRootCoordSpace( + gfx::ToRoundedPoint(point))); } void RenderWidgetHostViewBase::TransformPointToLocalCoordSpace(
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index d714137..fa223b8 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -88,6 +88,12 @@ scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override; void EndFrameSubscription() override; + // This only needs to be overridden by RenderWidgetHostViewBase subclasses + // that handle content embedded within other RenderWidgetHostViews. + gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point) override; + gfx::PointF TransformPointToRootCoordSpaceF( + const gfx::PointF& point) override; + // IPC::Listener implementation: bool OnMessageReceived(const IPC::Message& msg) override; @@ -204,15 +210,6 @@ virtual void ProcessTouchEvent(const blink::WebTouchEvent& event, const ui::LatencyInfo& latency) {} - // If a RenderWidgetHost is dealing with points that are transformed from the - // root frame for a page (i.e. because its content is contained within - // that of another RenderWidgetHost), this provides a facility to convert - // a point from its own coordinate space to that of the root frame. - // This only needs to be overriden by RenderWidgetHostView subclasses - // that handle content embedded within other RenderWidgetHostViews. - virtual void TransformPointToRootCoordSpace(const gfx::Point& point, - gfx::Point* transformed_point); - // Transform a point that is in the coordinate space of a Surface that is // embedded within the RenderWidgetHostViewBase's Surface to the // coordinate space of the embedding Surface. Typically this means that a
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index d427d92..67318be 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -602,6 +602,20 @@ } }; +// SitePerProcessIgnoreCertErrorsBrowserTest + +class SitePerProcessIgnoreCertErrorsBrowserTest + : public SitePerProcessBrowserTest { + public: + SitePerProcessIgnoreCertErrorsBrowserTest() {} + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + SitePerProcessBrowserTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); + } +}; + // Ensure that navigating subframes in --site-per-process mode works and the // correct documents are committed. IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) { @@ -4984,4 +4998,104 @@ EXPECT_EQ(b_url.GetOrigin().spec(), popup_origin + "/"); } +// Tests that the WebContents is notified when passive mixed content is +// displayed in an OOPIF. The test ignores cert errors so that an HTTPS +// iframe can be loaded from a site other than localhost (the +// EmbeddedTestServer serves a certificate that is valid for localhost). +IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, + PassiveMixedContentInIframe) { + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(https_server.Start()); + SetupCrossSiteRedirector(&https_server); + + GURL iframe_url( + https_server.GetURL("/mixed-content/basic-passive-in-iframe.html")); + EXPECT_TRUE(NavigateToURL(shell(), iframe_url)); + EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent()); + + // When the subframe navigates, the WebContents should still be marked + // as having displayed insecure content. + GURL navigate_url(https_server.GetURL("/title1.html")); + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + NavigateFrameToURL(root->child_at(0), navigate_url); + EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent()); + + // When the main frame navigates, it should no longer be marked as + // displaying insecure content. + EXPECT_TRUE( + NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html"))); + EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent()); +} + +// Tests that, when a parent frame is set to strictly block mixed +// content via Content Security Policy, child OOPIFs cannot display +// mixed content. +IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, + PassiveMixedContentInIframeWithStrictBlocking) { + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(https_server.Start()); + SetupCrossSiteRedirector(&https_server); + + GURL iframe_url_with_strict_blocking(https_server.GetURL( + "/mixed-content/basic-passive-in-iframe-with-strict-blocking.html")); + EXPECT_TRUE(NavigateToURL(shell(), iframe_url_with_strict_blocking)); + EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent()); + + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + EXPECT_TRUE(root->current_replication_state() + .should_enforce_strict_mixed_content_checking); + EXPECT_TRUE(root->child_at(0) + ->current_replication_state() + .should_enforce_strict_mixed_content_checking); + + // When the subframe navigates, it should still be marked as enforcing + // strict mixed content. + GURL navigate_url(https_server.GetURL("/title1.html")); + NavigateFrameToURL(root->child_at(0), navigate_url); + EXPECT_TRUE(root->current_replication_state() + .should_enforce_strict_mixed_content_checking); + EXPECT_TRUE(root->child_at(0) + ->current_replication_state() + .should_enforce_strict_mixed_content_checking); + + // When the main frame navigates, it should no longer be marked as + // enforcing strict mixed content. + EXPECT_TRUE( + NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html"))); + EXPECT_FALSE(root->current_replication_state() + .should_enforce_strict_mixed_content_checking); +} + +// Tests that active mixed content is blocked in an OOPIF. The test +// ignores cert errors so that an HTTPS iframe can be loaded from a site +// other than localhost (the EmbeddedTestServer serves a certificate +// that is valid for localhost). +IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, + ActiveMixedContentInIframe) { + net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_server.ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(https_server.Start()); + SetupCrossSiteRedirector(&https_server); + + GURL iframe_url( + https_server.GetURL("/mixed-content/basic-active-in-iframe.html")); + EXPECT_TRUE(NavigateToURL(shell(), iframe_url)); + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + ASSERT_EQ(1U, root->child_count()); + FrameTreeNode* mixed_child = root->child_at(0)->child_at(0); + ASSERT_TRUE(mixed_child); + // The child iframe attempted to create a mixed iframe; this should + // have been blocked, so the mixed iframe should not have committed a + // load. + EXPECT_FALSE(mixed_child->has_committed_real_load()); +} + } // namespace content
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 70edf234..59e1dbd 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -12,6 +12,7 @@ #include "base/sys_info.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "components/tracing/process_metrics_memory_dump_provider.h" #include "content/browser/tracing/file_tracing_provider_impl.h" #include "content/browser/tracing/power_tracing_agent.h" #include "content/browser/tracing/trace_message_filter.h" @@ -557,6 +558,13 @@ return; } +#if defined(OS_LINUX) + // On Linux the browser process dumps process metrics for child process due to + // sandbox. + tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( + trace_message_filter->peer_pid()); +#endif + trace_message_filters_.insert(trace_message_filter); if (can_cancel_watch_event()) { trace_message_filter->SendSetWatchEvent(watch_category_name_, @@ -585,6 +593,11 @@ return; } +#if defined(OS_LINUX) + tracing::ProcessMetricsMemoryDumpProvider::UnregisterForProcess( + trace_message_filter->peer_pid()); +#endif + // If a filter is removed while a response from that filter is pending then // simulate the response. Otherwise the response count will be wrong and the // completion callback will never be executed.
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 95e23f0..510b0fe 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -375,6 +375,8 @@ IPC_STRUCT_TRAITS_MEMBER(origin) IPC_STRUCT_TRAITS_MEMBER(sandbox_flags) IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(scope) + IPC_STRUCT_TRAITS_MEMBER(should_enforce_strict_mixed_content_checking) IPC_STRUCT_TRAITS_END() IPC_STRUCT_BEGIN(FrameMsg_NewFrame_WidgetParams)
diff --git a/content/common/media/media_session_messages_android.h b/content/common/media/media_session_messages_android.h index 18a63844..266ee27 100644 --- a/content/common/media/media_session_messages_android.h +++ b/content/common/media/media_session_messages_android.h
@@ -7,12 +7,19 @@ #include "content/common/android/gin_java_bridge_errors.h" #include "content/common/content_export.h" +#include "content/public/common/media_metadata.h" #include "ipc/ipc_message_macros.h" #undef IPC_MESSAGE_EXPORT #define IPC_MESSAGE_EXPORT CONTENT_EXPORT #define IPC_MESSAGE_START MediaSessionMsgStart +IPC_STRUCT_TRAITS_BEGIN(content::MediaMetadata) + IPC_STRUCT_TRAITS_MEMBER(title) + IPC_STRUCT_TRAITS_MEMBER(artist) + IPC_STRUCT_TRAITS_MEMBER(album) +IPC_STRUCT_TRAITS_END() + // Messages for notifying the render process of media session status ------- IPC_MESSAGE_ROUTED2(MediaSessionMsg_DidActivate, @@ -30,3 +37,7 @@ IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_Deactivate, int /* session_id */, int /* request_id */) + +IPC_MESSAGE_ROUTED2(MediaSessionHostMsg_SetMetadata, + int /* request_id*/, + content::MediaMetadata /* metadata */)
diff --git a/content/content_common.gypi b/content/content_common.gypi index 1231847..5bcd2a8 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -87,6 +87,8 @@ 'public/common/main_function_params.h', 'public/common/manifest.cc', 'public/common/manifest.h', + 'public/common/media_metadata.cc', + 'public/common/media_metadata.h', 'public/common/media_stream_request.cc', 'public/common/media_stream_request.h', 'public/common/menu_item.cc',
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h index a8f71fe3..a2e497e7 100644 --- a/content/public/browser/render_frame_host.h +++ b/content/public/browser/render_frame_host.h
@@ -26,6 +26,7 @@ namespace content { class RenderProcessHost; class RenderViewHost; +class RenderWidgetHostView; class ServiceRegistry; class SiteInstance; @@ -73,6 +74,10 @@ // Returns the process for this frame. virtual RenderProcessHost* GetProcess() = 0; + // Returns the RenderWidgetHostView that can be used to control focus and + // visibility for this frame. + virtual RenderWidgetHostView* GetView() = 0; + // Returns the current RenderFrameHost of the parent frame, or nullptr if // there is no parent. The result may be in a different process than the // current RenderFrameHost.
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h index 9b48ddb..7c749a2 100644 --- a/content/public/browser/render_widget_host_view.h +++ b/content/public/browser/render_widget_host_view.h
@@ -65,6 +65,19 @@ // Retrieves the last known scroll position. virtual gfx::Vector2dF GetLastScrollOffset() const = 0; + // Coordinate points received from a renderer process need to be transformed + // to the top-level frame's coordinate space. For coordinates received from + // the top-level frame's renderer this is a no-op as they are already + // properly transformed; however, coordinates received from an out-of-process + // iframe renderer process require transformation. + virtual gfx::Point TransformPointToRootCoordSpace( + const gfx::Point& point) = 0; + + // A floating point variant of the above. PointF values will be snapped to + // integral points before transformation. + virtual gfx::PointF TransformPointToRootCoordSpaceF( + const gfx::PointF& point) = 0; + // Retrieves the native view used to contain plugins and identify the // renderer in IPC messages. virtual gfx::NativeView GetNativeView() const = 0;
diff --git a/content/public/common/media_metadata.cc b/content/public/common/media_metadata.cc new file mode 100644 index 0000000..dc3824c2 --- /dev/null +++ b/content/public/common/media_metadata.cc
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/common/media_metadata.h" + +namespace content { + +const size_t MediaMetadata::kMaxIPCStringLength = 4 * 1024; + +MediaMetadata::MediaMetadata() = default; + +MediaMetadata::~MediaMetadata() = default; + +bool MediaMetadata::operator==(const MediaMetadata& other) const { + return title == other.title && artist == other.artist && album == other.album; +} + +bool MediaMetadata::operator!=(const MediaMetadata& other) const { + return !this->operator==(other); +} + +} // namespace content
diff --git a/content/public/common/media_metadata.h b/content/public/common/media_metadata.h new file mode 100644 index 0000000..3d7f13c --- /dev/null +++ b/content/public/common/media_metadata.h
@@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_COMMON_MEDIA_METADATA_H_ +#define CONTENT_PUBLIC_COMMON_MEDIA_METADATA_H_ + +#include "base/strings/string16.h" +#include "content/common/content_export.h" + +namespace content { + +// The MediaMetadata is a structure carrying information associated to a +// content::MediaSession. +struct CONTENT_EXPORT MediaMetadata { + MediaMetadata(); + ~MediaMetadata(); + + bool operator==(const MediaMetadata& other) const; + bool operator!=(const MediaMetadata& other) const; + + // Title associated to the MediaSession. + base::string16 title; + + // Artist associated to the MediaSession. + base::string16 artist; + + // Album associated to the MediaSession. + base::string16 album; + + // Maximum length for all the strings inside the MediaMetadata when it is sent + // over IPC. The renderer process should truncate the strings before sending + // the MediaMetadata and the browser process must do the same when receiving + // it. + static const size_t kMaxIPCStringLength; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_COMMON_MEDIA_METADATA_H_
diff --git a/content/renderer/media/android/renderer_media_session_manager.cc b/content/renderer/media/android/renderer_media_session_manager.cc index 58b0888..2670a4a38 100644 --- a/content/renderer/media/android/renderer_media_session_manager.cc +++ b/content/renderer/media/android/renderer_media_session_manager.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "content/common/media/media_session_messages_android.h" +#include "content/public/common/media_metadata.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/media/android/webmediasession_android.h" @@ -59,6 +60,23 @@ new MediaSessionHostMsg_Deactivate(routing_id(), session_id, request_id)); } +void RendererMediaSessionManager::SetMetadata( + int session_id, + const MediaMetadata& metadata) { + // Apply some sanity checks on the MediaMetadata before sending over IPC. + MediaMetadata ipc_metadata; + ipc_metadata.title = + metadata.title.substr(0, MediaMetadata::kMaxIPCStringLength); + ipc_metadata.artist = + metadata.artist.substr(0, MediaMetadata::kMaxIPCStringLength); + ipc_metadata.album = + metadata.album.substr(0, MediaMetadata::kMaxIPCStringLength); + + Send(new MediaSessionHostMsg_SetMetadata(routing_id(), + session_id, + ipc_metadata)); +} + void RendererMediaSessionManager::OnDidActivate(int request_id, bool success) { DCHECK(pending_activation_requests_.Lookup(request_id)) << request_id; blink::WebMediaSessionActivateCallback* callback =
diff --git a/content/renderer/media/android/renderer_media_session_manager.h b/content/renderer/media/android/renderer_media_session_manager.h index c7f75044..5c5a2f2 100644 --- a/content/renderer/media/android/renderer_media_session_manager.h +++ b/content/renderer/media/android/renderer_media_session_manager.h
@@ -16,6 +16,7 @@ namespace content { class WebMediaSessionAndroid; +struct MediaMetadata; class CONTENT_EXPORT RendererMediaSessionManager : public RenderFrameObserver { public: @@ -33,6 +34,7 @@ void Deactivate( int session_id, scoped_ptr<blink::WebMediaSessionDeactivateCallback> callback); + void SetMetadata(int session_id, const MediaMetadata& metadata); void OnDidActivate(int request_id, bool success); void OnDidDeactivate(int request_id);
diff --git a/content/renderer/media/android/webmediasession_android.cc b/content/renderer/media/android/webmediasession_android.cc index b10d5f26..ddfa13c7 100644 --- a/content/renderer/media/android/webmediasession_android.cc +++ b/content/renderer/media/android/webmediasession_android.cc
@@ -6,7 +6,9 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "content/public/common/media_metadata.h" #include "content/renderer/media/android/renderer_media_session_manager.h" +#include "third_party/WebKit/public/platform/modules/mediasession/WebMediaMetadata.h" namespace content { @@ -32,8 +34,15 @@ } void WebMediaSessionAndroid::setMetadata( - const blink::WebMediaMetadata* metadata) { - NOTIMPLEMENTED(); + const blink::WebMediaMetadata* web_metadata) { + MediaMetadata metadata; + if (web_metadata) { + metadata.title = web_metadata->title; + metadata.artist = web_metadata->artist; + metadata.album = web_metadata->album; + } + + session_manager_->SetMetadata(session_id_, metadata); } } // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index ad0e0ab..75e77b4 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2423,7 +2423,8 @@ WebMediaPlayerClient* client, WebMediaPlayerEncryptedMediaClient* encrypted_client, WebContentDecryptionModule* initial_cdm, - const blink::WebString& sink_id) { + const blink::WebString& sink_id, + WebMediaSession* media_session) { #if defined(VIDEO_HOLE) if (!contains_media_player_) { render_view_->RegisterVideoHoleFrame(this);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index cd1f5987..f9cf06c 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -419,7 +419,8 @@ blink::WebMediaPlayerClient* client, blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, blink::WebContentDecryptionModule* initial_cdm, - const blink::WebString& sink_id) override; + const blink::WebString& sink_id, + blink::WebMediaSession* media_session) override; blink::WebMediaSession* createMediaSession() override; blink::WebApplicationCacheHost* createApplicationCacheHost( blink::WebLocalFrame* frame,
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc index 2e1e4ff..a16fdc00 100644 --- a/content/shell/browser/shell_views.cc +++ b/content/shell/browser/shell_views.cc
@@ -54,23 +54,6 @@ namespace content { namespace { -// ViewDelegate implementation for aura content shell -class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate { - public: - ShellViewsDelegateAura() : use_transparent_windows_(false) { - } - - ~ShellViewsDelegateAura() override {} - - void SetUseTransparentWindows(bool transparent) { - use_transparent_windows_ = transparent; - } - - private: - bool use_transparent_windows_; - - DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura); -}; // Model for the "Debug" menu class ContextMenuModel : public ui::SimpleMenuModel, @@ -421,7 +404,7 @@ gfx::Screen::SetScreenInstance( gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); #endif - views_delegate_ = new ShellViewsDelegateAura(); + views_delegate_ = new views::DesktopTestViewsDelegate(); } void Shell::PlatformExit() {
diff --git a/content/test/data/mixed-content/basic-active-in-iframe.html b/content/test/data/mixed-content/basic-active-in-iframe.html new file mode 100644 index 0000000..9e2438f --- /dev/null +++ b/content/test/data/mixed-content/basic-active-in-iframe.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> +</head> + +<body> +</body> +<iframe src="/cross-site/a.com/mixed-content/basic-active.html"></iframe> +</html>
diff --git a/content/test/data/mixed-content/basic-active.html b/content/test/data/mixed-content/basic-active.html new file mode 100644 index 0000000..96ec3b3 --- /dev/null +++ b/content/test/data/mixed-content/basic-active.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<body> + <iframe src="http://a.test"></iframe> +</body> +</html>
diff --git a/content/test/data/mixed-content/basic-passive-in-iframe-with-strict-blocking.html b/content/test/data/mixed-content/basic-passive-in-iframe-with-strict-blocking.html new file mode 100644 index 0000000..5ef54ce --- /dev/null +++ b/content/test/data/mixed-content/basic-passive-in-iframe-with-strict-blocking.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> +</head> +<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content"> +<body> + <iframe src="/cross-site/a.com/mixed-content/basic-passive.html"></iframe> +</body> +</html>
diff --git a/content/test/data/mixed-content/basic-passive-in-iframe.html b/content/test/data/mixed-content/basic-passive-in-iframe.html new file mode 100644 index 0000000..5d10e96 --- /dev/null +++ b/content/test/data/mixed-content/basic-passive-in-iframe.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> +</head> + +<body> + <iframe src="/cross-site/a.com/mixed-content/basic-passive.html"></iframe> +</body> +</html>
diff --git a/content/test/data/mixed-content/basic-passive.html b/content/test/data/mixed-content/basic-passive.html new file mode 100644 index 0000000..b639b55f --- /dev/null +++ b/content/test/data/mixed-content/basic-passive.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<head> +</head> + +<body> +This page tries to load some passive mixed content. +<img src="http://a.test/image.jpg" /> +</body> +</html>
diff --git a/docs/updating_clang_format_binaries.md b/docs/updating_clang_format_binaries.md index 8ba14ae3..0e10f49 100644 --- a/docs/updating_clang_format_binaries.md +++ b/docs/updating_clang_format_binaries.md
@@ -76,8 +76,6 @@ -DCMAKE_C_COMPILER=$PWD/../chrome/src/third_party/llvm-build/Release+Asserts/bin/clang -DCMAKE_CXX_COMPILER=$PWD/../chrome/src/third_party/llvm-build/Release+Asserts/bin/clang++ ``` -TODO: these ^^ instructions looks odd. Are they correct??? - Platform specific notes: * Windows: Visual Studio 2013 only.
diff --git a/docs/writing_clang_plugins.md b/docs/writing_clang_plugins.md index b8a65f6..4ca801a0 100644 --- a/docs/writing_clang_plugins.md +++ b/docs/writing_clang_plugins.md
@@ -2,11 +2,6 @@ [TOC] -TODO: although cs.chromium.org -[finds](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/llvm/) -`src/third_party/llvm`, it -[does not exist in Gitiles](https://chromium.googlesource.com/src/third_party/llvm/). - Make sure you really want to write a clang plugin. * The clang plugin api is not stable. If you write a plugin, _you_ are
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc index 50de79fe..68c4bd1f 100644 --- a/extensions/renderer/module_system_test.cc +++ b/extensions/renderer/module_system_test.cc
@@ -22,7 +22,6 @@ #include "extensions/renderer/object_backed_native_handler.h" #include "extensions/renderer/safe_builtins.h" #include "extensions/renderer/utils_native_handler.h" -#include "third_party/WebKit/public/web/WebHeap.h" #include "ui/base/resource/resource_bundle.h" namespace extensions { @@ -241,7 +240,6 @@ old_heap_size = stats.used_heap_size(); isolate_->RequestGarbageCollectionForTesting( v8::Isolate::kFullGarbageCollection); - blink::WebHeap::collectAllGarbageForTesting(); isolate_->GetHeapStatistics(&stats); } }
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h index 84c2cc2f..a89326487 100644 --- a/ios/chrome/browser/experimental_flags.h +++ b/ios/chrome/browser/experimental_flags.h
@@ -53,6 +53,9 @@ // Whether the Tab Switcher is enabled for iPad or not. bool IsTabSwitcherEnabled(); +// Whether the reading list is enabled. +bool IsReadingListEnabled(); + } // namespace experimental_flags #endif // IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index b6c537c9..297172d 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -28,6 +28,7 @@ NSString* const kHeuristicsForPasswordGeneration = @"HeuristicsForPasswordGeneration"; const char* const kWKWebViewTrialName = "IOSUseWKWebView"; +NSString* const kEnableReadingList = @"EnableReadingList"; enum class WKWebViewEligibility { // UNSET indicates that no explicit call to set eligibility has been made, @@ -230,4 +231,8 @@ base::CompareCase::INSENSITIVE_ASCII); } +bool IsReadingListEnabled() { + return [[NSUserDefaults standardUserDefaults] boolForKey:kEnableReadingList]; +} + } // namespace experimental_flags
diff --git a/mojo/public/interfaces/bindings/tests/test_native_types.mojom b/mojo/public/interfaces/bindings/tests/test_native_types.mojom index 1012756..e0767f3 100644 --- a/mojo/public/interfaces/bindings/tests/test_native_types.mojom +++ b/mojo/public/interfaces/bindings/tests/test_native_types.mojom
@@ -8,7 +8,7 @@ // Used to verify that structs can be declared with no body in mojom. -[native=True] +[Native=True] struct PickledStruct; interface PicklePasser {
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/mojo/public/tools/bindings/pylib/mojom/generate/data.py index 60ae1e0..e8c71f3 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/data.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/data.py
@@ -225,12 +225,12 @@ struct.fields_data = data['fields'] struct.attributes = data.get('attributes') - # Enforce that a [native=True] attribute is set to make native-only struct + # Enforce that a [Native=True] attribute is set to make native-only struct # declarations more explicit. if struct.native_only: - if not struct.attributes or not struct.attributes.get('native', False): + if not struct.attributes or not struct.attributes.get('Native', False): raise Exception("Native-only struct declarations must include a " + - "native=True attribute.") + "Native=True attribute.") return struct
diff --git a/net/net_unittests_apk.isolate b/net/net_unittests_apk.isolate index b1e945b..07ef728 100644 --- a/net/net_unittests_apk.isolate +++ b/net/net_unittests_apk.isolate
@@ -10,6 +10,7 @@ 'variables': { 'command': [ '<(PRODUCT_DIR)/bin/run_net_unittests', + '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats', ], 'files': [ '../base/base.isolate',
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java index 7e8e205..aaea7aa 100644 --- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java +++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -9,6 +9,7 @@ import android.accounts.Account; import android.accounts.AuthenticatorDescription; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Process; @@ -298,13 +299,16 @@ */ public void getAuthToken(final Account account, final String authTokenType, final GetAuthTokenCallback callback) { - ConnectionRetry.runAuthTask(new AuthTask<String>() { + ConnectionRetry.runAuthTask(mApplicationContext, new AuthTask<String>() { + @Override public String run() throws AuthException { return mAccountManager.getAuthToken(account, authTokenType); } + @Override public void onSuccess(String token) { callback.tokenAvailable(token); } + @Override public void onFailure(boolean isTransientError) { callback.tokenUnavailable(isTransientError); } @@ -334,12 +338,15 @@ if (authToken == null || authToken.isEmpty()) { return; } - ConnectionRetry.runAuthTask(new AuthTask<Boolean>() { + ConnectionRetry.runAuthTask(mApplicationContext, new AuthTask<Boolean>() { + @Override public Boolean run() throws AuthException { mAccountManager.invalidateAuthToken(authToken); return true; } + @Override public void onSuccess(Boolean result) {} + @Override public void onFailure(boolean isTransientError) { Log.e(TAG, "Failed to invalidate auth token: " + authToken); } @@ -367,15 +374,17 @@ implements NetworkChangeNotifier.ConnectionTypeObserver { private static final int MAX_TRIES = 3; + private final Context mContext; private final AuthTask<T> mAuthTask; private final AtomicInteger mNumTries; private final AtomicBoolean mIsTransientError; - public static <T> void runAuthTask(AuthTask<T> authTask) { - new ConnectionRetry<T>(authTask).attempt(); + public static <T> void runAuthTask(Context context, AuthTask<T> authTask) { + new ConnectionRetry<T>(context, authTask).attempt(); } - private ConnectionRetry(AuthTask<T> authTask) { + private ConnectionRetry(Context context, AuthTask<T> authTask) { + mContext = context; mAuthTask = authTask; mNumTries = new AtomicInteger(0); mIsTransientError = new AtomicBoolean(false); @@ -394,9 +403,17 @@ try { return mAuthTask.run(); } catch (AuthException ex) { - // TODO(547048): Handle the recovery intent if it is present. - Log.e(TAG, "Failed to perform auth task", ex); + Log.w(TAG, "Failed to perform auth task", ex); mIsTransientError.set(ex.isTransientError()); + + // TODO(547048): This will fire the intent indiscriminately. We should fix + // this in the future to fire only once per user actionable intent to avoid + // spamming the user. + if (ex.getRecoveryIntent() != null) { + Intent i = ex.getRecoveryIntent(); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(i); + } } return null; }
diff --git a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html index 55c695b..6cebf37 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html +++ b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html
@@ -117,6 +117,30 @@ }, testSpec.testName); }); +// TODO(ortuno): Allow connections when the tab is in the background. +// This is a short term solution instead of implementing a tab indicator +// for bluetooth connections. +// https://crbug.com/579746 +promise_test(() => { + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + testRunner.setPageVisibility('hidden'); + return assert_promise_rejects_with_message( + device.connectGATT(), + new DOMException('Connection is only allowed while the page is visible. ' + + 'This is a temporary measure until we are able to ' + + 'effectively communicate to the user that a page is ' + + 'connected to a device.', + 'SecurityError')); + }) + .then(() => testRunner.setPageVisibility('visible')) + .catch(error => { + testRunner.setPageVisibility('visible'); + throw error; + }); +}, 'Device should not be able to connect in background.'); + promise_test(() => { testRunner.setBluetoothMockDataSet('HeartRateAdapter'); return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
diff --git a/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/detach-gc.html b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/detach-gc.html new file mode 100644 index 0000000..28f2cdb --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/detach-gc.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/bluetooth-helpers.js"></script> +<body> + <script> + "use strict"; + async_test(test => { + window.onmessage = messageEvent => test.step(() => { + if (messageEvent.data === 'Ready') { + let iframe = document.querySelector('iframe'); + callWithKeyDown(() => { + iframe.contentWindow.postMessage('Go', '*'); + }); + } else if (messageEvent.data === 'Connected') { + // Detach + iframe.remove(); + // GC + runGarbageCollection().then(() => test.done()); + } else { + assert_unreached('iframe sent invalid data: ' + messageEvent.data); + } + }); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + let iframe = document.createElement('iframe'); + iframe.src = '../resources/connectGATT-iframe.html'; + document.body.appendChild(iframe); + }, 'Detach frame then garbage collect. We shouldn\'t crash.'); + </script> +</body>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/gc-detach.html b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/gc-detach.html new file mode 100644 index 0000000..e5b4fda --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/gc-detach.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/bluetooth-helpers.js"></script> +<body> + <script> + "use strict"; + async_test(test => { + window.onmessage = messageEvent => test.step(() => { + if (messageEvent.data === 'Ready') { + let iframe = document.querySelector('iframe'); + callWithKeyDown(() => { + iframe.contentWindow.postMessage('Go', '*'); + }); + } else if (messageEvent.data === 'Connected') { + // GC + runGarbageCollection().then(() => { + // Detach + iframe.remove(); + test.done(); + }); + } else { + assert_unreached('iframe sent invalid data: ' + messageEvent.data); + } + }); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + let iframe = document.createElement('iframe'); + iframe.src = '../resources/connectGATT-iframe.html'; + document.body.appendChild(iframe); + }, 'Garbage collect then detach frame. We shouldn\'t crash.'); + </script> +</body>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/hide-detach.html b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/hide-detach.html new file mode 100644 index 0000000..59bff78 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/disconnect-frame-detached/hide-detach.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/bluetooth-helpers.js"></script> +<body> + <script> + "use strict"; + async_test(test => { + window.onmessage = messageEvent => test.step(() => { + if (messageEvent.data === 'Ready') { + let iframe = document.querySelector('iframe'); + callWithKeyDown(() => { + iframe.contentWindow.postMessage('Go', '*'); + }); + } else if (messageEvent.data === 'Connected') { + // Hide + testRunner.setPageVisibility('hidden'); + // Detach + iframe.remove(); + test.done(); + } else { + assert_unreached('iframe sent invalid data: ' + messageEvent.data); + } + }); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + let iframe = document.createElement('iframe'); + iframe.src = '../resources/connectGATT-iframe.html'; + document.body.appendChild(iframe); + }, 'Hide then detach frame. We shouldn\'t crash.'); + </script> +</body>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/disconnect-when-hidden-or-closed.html b/third_party/WebKit/LayoutTests/bluetooth/disconnect-when-hidden-or-closed.html new file mode 100644 index 0000000..fcf3ca0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/disconnect-when-hidden-or-closed.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="resources/bluetooth-helpers.js"></script> +<script> +'use strict'; +test(t => { assert_true(window.testRunner instanceof Object); t.done(); }, + 'window.testRunner is required for the following tests.'); + +// TODO(ortuno): Allow connections when the tab is in the background. +// This is a short term solution instead of implementing a tab indicator +// for bluetooth connections. +// https://crbug.com/579746 +promise_test(() => { + testRunner.setPageVisibility("visible"); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => device.connectGATT()) + .then(gatt_server => { + assert_true(gatt_server.connected); + testRunner.setPageVisibility("hidden"); + assert_false(gatt_server.connected); + testRunner.setPageVisibility("visible"); + assert_false(gatt_server.connected); + }); +}, 'Test device disconnects when tab becomes hidden'); + +promise_test(() => { + testRunner.setPageVisibility('visible'); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => device.connectGATT()) + .then(gatt_server => {}) + .then(() => runGarbageCollection()) + .then(() => testRunner.setPageVisibility('hidden')); +}, 'Test object gets garbage collected before tab becomes hidden. ' + + 'We shouldn\'t crash.'); + +promise_test(() => { + testRunner.setPageVisibility('visible'); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => device.connectGATT()) + .then(gatt_server => testRunner.setPageVisibility('hidden')) + .then(() => runGarbageCollection()); +}, 'Test object gets garbage collected after tab becomes hidden. ' + + 'We shouldn\'t crash.'); + +promise_test(() => { + testRunner.setPageVisibility('visible'); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + let connect_promise = device.connectGATT(); + testRunner.setPageVisibility('hidden'); + return connect_promise; + }).then(gatt_server => { + assert_false(gatt_server.connected); + }); +}, 'Visibility changes during connection. Should disconnect.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/resources/connectGATT-iframe.html b/third_party/WebKit/LayoutTests/bluetooth/resources/connectGATT-iframe.html new file mode 100644 index 0000000..7c5fa721 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/resources/connectGATT-iframe.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<script> + window.onmessage = messageEvent => { + if (messageEvent.data === 'Go') { + navigator.bluetooth.requestDevice({ + filters: [{services: ['heart_rate']}] + }) + .then(device => device.connectGATT()) + .then(gattServer => { + parent.postMessage('Connected', '*'); + }).catch(err => { + console.error(err); + parent.postMessage('FAIL: ' + err, '*'); + }); + } + }; + parent.postMessage("Ready", "*"); +</script>
diff --git a/third_party/WebKit/LayoutTests/css-parser/ascii-case-insensitive-matching.html b/third_party/WebKit/LayoutTests/css-parser/ascii-case-insensitive-matching.html new file mode 100644 index 0000000..fcca0108 --- /dev/null +++ b/third_party/WebKit/LayoutTests/css-parser/ascii-case-insensitive-matching.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<style> +#a { + width: 100px; + height: 100px; + background-color: green; +} + +@support\017f (background-color: red) { + #a { + background-color: red; + } +} +</style> +<div id=a></div> +<script> +test(function() { + assert_equals(getComputedStyle(a).backgroundColor, "rgb(0, 128, 0)"); +}, "Identifier values are matched ASCII case-insensitively"); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-allowed.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-allowed.html new file mode 100644 index 0000000..e71fd0b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-allowed.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Security-Policy" content="connect-src http://127.0.0.1:8000; script-src http://127.0.0.1:8000 'unsafe-inline'"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<link rel=preload href="../../resources/dummy.js" id=preload> +<script> + var t = async_test('Makes sure that connect-src allows link preload resources with no as type'); + var preload = document.getElementById("preload"); + preload.onload = t.step(function(){ + t.done(); + }); +</script> +</head> +<body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-blocked.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-blocked.html new file mode 100644 index 0000000..efd3cf0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/connect-src-preload-blocked.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Security-Policy" content="connect-src http://foobar.test:8000; script-src http://127.0.0.1:8000 'unsafe-inline'"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<link rel=preload href="../../resources/dummy.js" id=preload> +<script> + var t = async_test('Makes sure that connect-src allows link preload resources with no as type'); + var preload = document.getElementById("preload"); + preload.onerror = t.step(function(){ + t.done(); + }); +</script> +</head> +<body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/active-subresource-in-iframe-blocked.https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/active-subresource-in-iframe-blocked.https-expected.txt index 00de7b8..109e3adc 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/active-subresource-in-iframe-blocked.https-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/active-subresource-in-iframe-blocked.https-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE ERROR: line 4: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css.html' was loaded over HTTPS, but requested an insecure stylesheet 'http://127.0.0.1:8080/security/mixedContent/resources/style.css'. This request has been blocked; the content must be served over HTTPS. +CONSOLE ERROR: line 4: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/active-subresource-in-iframe-blocked.https.html' was loaded over HTTPS, but requested an insecure stylesheet 'http://127.0.0.1:8080/security/mixedContent/resources/style.css'. This request has been blocked; the content must be served over HTTPS. This test passes if the active subresource in the frame below is blocked.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-image-with-reload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-image-with-reload-expected.txt index 488843b..38d63e8e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-image-with-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-css-image-with-reload-expected.txt
@@ -1,5 +1,5 @@ -CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css-image.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-subframe-and-reload.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This content should also be served over HTTPS. CONSOLE MESSAGE: line 12: Reloading... -CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-css-image.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-subframe-and-reload.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This content should also be served over HTTPS. CONSOLE MESSAGE: line 17: Second load finished. This test opens a window that loads a frame with a subframe which contains insecure css image. The subframe is refreshed after it loads. We should trigger a mixed content callback twice despite the fact that on a second load of the subframe a css cache might be used to fetch an image.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-frame-in-data-iframe-in-main-frame-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-frame-in-data-iframe-in-main-frame-blocked-expected.txt index d4979374b..bf3d5473 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-frame-in-data-iframe-in-main-frame-blocked-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-frame-in-data-iframe-in-main-frame-blocked-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 1: Mixed Content: The page at 'data:text/html,<html><iframe src='http://127.0.0.1:8080/security/mixedContent/resources/boring.html'></iframe></html>' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This request has been blocked; the content must be served over HTTPS. +CONSOLE ERROR: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-data-url-frame-with-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This request has been blocked; the content must be served over HTTPS. This test opens a window that loads a data: iframe that loads an insecure frame, and that the frame is still blocked.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-iframe-expected.txt index f21296cc..c4d88439 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-iframe-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-iframe-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE WARNING: line 8: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. This test loads a secure iframe that loads an insecure iframe. We should get a mixed content callback becase the child frame is HTTPS.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-allowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-allowed-expected.txt index 062e4398..55e67f1 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-allowed-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-allowed-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE WARNING: line 9: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-iframe.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-iframe.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. This test opens a window that loads an insecure iframe. We should trigger a mixed content callback even though we've set the preference to block this, because we've overriden the preference via a web permission client callback.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-blocked-expected.txt index 0707e62..2d38a9b5 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-blocked-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-blocked-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: line 9: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-iframe.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This request has been blocked; the content must be served over HTTPS. +CONSOLE ERROR: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-iframe.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This request has been blocked; the content must be served over HTTPS. This test opens a window that loads an insecure iframe. We should not trigger a mixed content callback even though the main frame in the window is HTTPS and is displaying insecure content, because we've set the preference to block this.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-expected.txt index 00ba869..b270262 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-iframe-in-main-frame-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE WARNING: line 8: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. This test opens a window that loads an insecure iframe. We should trigger a mixed content callback because the main frame in the window is HTTPS but is running insecure content. ============== Back Forward List ==============
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-script-in-data-iframe-in-main-frame-blocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-script-in-data-iframe-in-main-frame-blocked-expected.txt index a5965de..61dcf77b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-script-in-data-iframe-in-main-frame-blocked-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-script-in-data-iframe-in-main-frame-blocked-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE ERROR: Mixed Content: The page at 'data:text/html,<html><script src='http://127.0.0.1:8080/security/mixedContent/resources/script.js'></script></html>' was loaded over HTTPS, but requested an insecure script 'http://127.0.0.1:8080/security/mixedContent/resources/script.js'. This request has been blocked; the content must be served over HTTPS. +CONSOLE ERROR: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-data-url-frame-with-script.html' was loaded over HTTPS, but requested an insecure script 'http://127.0.0.1:8080/security/mixedContent/resources/script.js'. This request has been blocked; the content must be served over HTTPS. This test opens a window that loads a data: iframe that loads an insecure script, and that the script is still blocked. Although the data: frame has a separate origin, the script can still navigate top.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https-expected.txt index 6107019..1179eb9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE WARNING: line 16: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https.html' was loaded over HTTPS, but requested an insecure resource 'nonwebbyscheme://this-will-fail-but-no-mixed-content-error-should-appear'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/nonwebby-scheme-in-iframe-allowed.https.html' was loaded over HTTPS, but requested an insecure resource 'nonwebbyscheme://this-will-fail-but-no-mixed-content-error-should-appear'. This content should also be served over HTTPS. This tests that non-webby URLs are not blocked as mixed content. The test passes if a mixed content warning is displayed and the load proceeds. The test fails if a mixed content error is displayed, and the load is blocked.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-http-to-https-iframe-in-main-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-http-to-https-iframe-in-main-frame-expected.txt index 7d6a912..f7a3beb0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-http-to-https-iframe-in-main-frame-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-http-to-https-iframe-in-main-frame-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE WARNING: line 8: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-redirect-http-to-https-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/resources/redir.php?url=https://127.0.0.1:8443/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-redirect-http-to-https-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/resources/redir.php?url=https://127.0.0.1:8443/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. This test opens a window that loads an insecure iframe (via a tricky redirect). We should trigger a mixed content callback because the main frame in the window is HTTPS but is running content that can be controlled by an active network attacker.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-https-to-http-iframe-in-main-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-https-to-http-iframe-in-main-frame-expected.txt index 7d6a912..f7a3beb0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-https-to-http-iframe-in-main-frame-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/redirect-https-to-http-iframe-in-main-frame-expected.txt
@@ -1,2 +1,2 @@ -CONSOLE WARNING: line 8: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-redirect-http-to-https-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/resources/redir.php?url=https://127.0.0.1:8443/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. +CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-redirect-http-to-https-frame.html' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:8080/security/resources/redir.php?url=https://127.0.0.1:8443/security/mixedContent/resources/boring.html'. This content should also be served over HTTPS. This test opens a window that loads an insecure iframe (via a tricky redirect). We should trigger a mixed content callback because the main frame in the window is HTTPS but is running content that can be controlled by an active network attacker.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/strict-mode-image-in-frame-blocked.https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/strict-mode-image-in-frame-blocked.https-expected.txt index 2a1ca3e..ad3fc2b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/strict-mode-image-in-frame-blocked.https-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/strict-mode-image-in-frame-blocked.https-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE ERROR: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-image.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This request has been blocked; the content must be served over HTTPS. +CONSOLE ERROR: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/strict-mode-image-in-frame-blocked.https.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8080/security/resources/compass.jpg'. This request has been blocked; the content must be served over HTTPS. This test passes if the image in the frame below is treated as blockable content.
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp index 92a837b..f81ce2f 100644 --- a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp +++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
@@ -160,7 +160,7 @@ toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)), toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes()); SVGPathByteStreamBuilder builder(*pathByteStream); - SVGPathParser(&source, &builder).parsePathDataFromSource(UnalteredParsing, false); + SVGPathParser(&source, &builder).parsePathDataFromSource(false); return pathByteStream.release(); }
diff --git a/third_party/WebKit/Source/core/css/CSSValueTestHelper.h b/third_party/WebKit/Source/core/css/CSSValueTestHelper.h index 59a3113..39b526a0 100644 --- a/third_party/WebKit/Source/core/css/CSSValueTestHelper.h +++ b/third_party/WebKit/Source/core/css/CSSValueTestHelper.h
@@ -39,7 +39,7 @@ #include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSValue.h" -#include <iostream> +#include <ostream> namespace testing { namespace internal {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSAtRuleID.cpp b/third_party/WebKit/Source/core/css/parser/CSSAtRuleID.cpp index 9276fbc..809d035 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSAtRuleID.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSAtRuleID.cpp
@@ -11,25 +11,25 @@ CSSAtRuleID cssAtRuleID(const CSSParserString& name) { - if (name.equalIgnoringCase("charset")) + if (name.equalIgnoringASCIICase("charset")) return CSSAtRuleCharset; - if (name.equalIgnoringCase("font-face")) + if (name.equalIgnoringASCIICase("font-face")) return CSSAtRuleFontFace; - if (name.equalIgnoringCase("import")) + if (name.equalIgnoringASCIICase("import")) return CSSAtRuleImport; - if (name.equalIgnoringCase("keyframes")) + if (name.equalIgnoringASCIICase("keyframes")) return CSSAtRuleKeyframes; - if (name.equalIgnoringCase("media")) + if (name.equalIgnoringASCIICase("media")) return CSSAtRuleMedia; - if (name.equalIgnoringCase("namespace")) + if (name.equalIgnoringASCIICase("namespace")) return CSSAtRuleNamespace; - if (name.equalIgnoringCase("page")) + if (name.equalIgnoringASCIICase("page")) return CSSAtRulePage; - if (name.equalIgnoringCase("supports")) + if (name.equalIgnoringASCIICase("supports")) return CSSAtRuleSupports; - if (name.equalIgnoringCase("viewport")) + if (name.equalIgnoringASCIICase("viewport")) return CSSAtRuleViewport; - if (name.equalIgnoringCase("-webkit-keyframes")) + if (name.equalIgnoringASCIICase("-webkit-keyframes")) return CSSAtRuleWebkitKeyframes; return CSSAtRuleInvalid; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp index 93be952e..47300c6 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -358,7 +358,7 @@ if (token.type() == StringToken || token.type() == UrlToken) return range.consumeIncludingWhitespace().value(); - if (token.type() != FunctionToken || !token.valueEqualsIgnoringCase("url")) + if (token.type() != FunctionToken || !token.valueEqualsIgnoringASCIICase("url")) return AtomicString(); CSSParserTokenRange contents = range.consumeBlock(); @@ -700,7 +700,7 @@ const CSSParserToken* last = range.end() - 1; while (last->type() == WhitespaceToken) --last; - if (last->type() == IdentToken && last->valueEqualsIgnoringCase("important")) { + if (last->type() == IdentToken && last->valueEqualsIgnoringASCIICase("important")) { --last; while (last->type() == WhitespaceToken) --last; @@ -748,9 +748,9 @@ const CSSParserToken& token = range.consumeIncludingWhitespace(); if (token.type() == PercentageToken && token.numericValue() >= 0 && token.numericValue() <= 100) result->append(token.numericValue() / 100); - else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("from")) + else if (token.type() == IdentToken && token.valueEqualsIgnoringASCIICase("from")) result->append(0); - else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("to")) + else if (token.type() == IdentToken && token.valueEqualsIgnoringASCIICase("to")) result->append(1); else return nullptr; // Parser error, invalid value in keyframe selector
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserString.h b/third_party/WebKit/Source/core/css/parser/CSSParserString.h index 0a83860f..7b868fd 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserString.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserString.h
@@ -81,13 +81,12 @@ return m_data.characters16[i]; } - bool equalIgnoringCase(const char* str) const + template<unsigned matchLength> + bool equalIgnoringASCIICase(const char (&match)[matchLength]) const { - bool match = is8Bit() ? WTF::equalIgnoringCase(str, characters8(), length()) : WTF::equalIgnoringCase(str, characters16(), length()); - if (!match) + if (matchLength - 1 != length()) return false; - ASSERT(strlen(str) >= length()); - return str[length()] == '\0'; + return is8Bit() ? WTF::equalIgnoringASCIICase(characters8(), match, length()) : WTF::equalIgnoringASCIICase(characters16(), match, length()); } operator String() const { return is8Bit() ? String(m_data.characters8, m_length) : StringImpl::create8BitIfPossible(m_data.characters16, m_length); }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserToken.h b/third_party/WebKit/Source/core/css/parser/CSSParserToken.h index 88d00dc..811db85 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserToken.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserToken.h
@@ -128,7 +128,8 @@ ret.initRaw(m_valueDataCharRaw, m_valueLength, m_valueIs8Bit); return ret; } - bool valueEqualsIgnoringCase(const char* str) const { return value().equalIgnoringCase(str); } + template<unsigned matchLength> + bool valueEqualsIgnoringASCIICase(const char (&match)[matchLength]) const { return value().equalIgnoringASCIICase<matchLength>(match); } UChar delimiter() const; NumericSign numericSign() const;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserValues.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserValues.cpp index 3aa4fe6..22d5adc 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserValues.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserValues.cpp
@@ -46,7 +46,7 @@ CSSParserValue value; switch (token.type()) { case FunctionToken: { - if (token.valueEqualsIgnoringCase("url")) { + if (token.valueEqualsIgnoringASCIICase("url")) { range.consume(); const CSSParserToken& next = range.consumeIncludingWhitespace(); if (next.type() == BadStringToken || range.consume().type() != RightParenthesisToken) { @@ -59,7 +59,8 @@ value.m_unit = CSSParserValue::URI; value.string = next.value(); break; - } else if (token.valueEqualsIgnoringCase("var")) { + } + if (token.valueEqualsIgnoringASCIICase("var")) { destroyAndClear(); return; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserValuesTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserValuesTest.cpp index 02944863..e73995d 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserValuesTest.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserValuesTest.cpp
@@ -59,20 +59,20 @@ EXPECT_FALSE(String(cssParserString).isNull()); } -TEST(CSSParserValuesTest, EqualIgnoringCase8BitsString) +TEST(CSSParserValuesTest, EqualIgnoringASCIICase8BitsString) { CSSParserString cssParserString; String string8bit("sHaDOw"); cssParserString.init(string8bit); - ASSERT_TRUE(cssParserString.equalIgnoringCase("shadow")); - ASSERT_TRUE(cssParserString.equalIgnoringCase("ShaDow")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("shadow-all")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("sha")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("abCD")); + ASSERT_TRUE(cssParserString.equalIgnoringASCIICase("shadow")); + ASSERT_TRUE(cssParserString.equalIgnoringASCIICase("ShaDow")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("shadow-all")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("sha")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("abCD")); } -TEST(CSSParserValuesTest, EqualIgnoringCase16BitsString) +TEST(CSSParserValuesTest, EqualIgnoringASCIICase16BitsString) { String string16bit("sHaDOw"); string16bit.ensure16Bit(); @@ -80,11 +80,21 @@ CSSParserString cssParserString; cssParserString.init(string16bit); - ASSERT_TRUE(cssParserString.equalIgnoringCase("shadow")); - ASSERT_TRUE(cssParserString.equalIgnoringCase("ShaDow")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("shadow-all")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("sha")); - ASSERT_FALSE(cssParserString.equalIgnoringCase("abCD")); + ASSERT_TRUE(cssParserString.equalIgnoringASCIICase("shadow")); + ASSERT_TRUE(cssParserString.equalIgnoringASCIICase("ShaDow")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("shadow-all")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("sha")); + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("abCD")); + + StringBuilder builder; + builder.append(0x017f); // LATIN SMALL LETTER LONG S + builder.append("HaDOw"); + ASSERT_FALSE(builder.is8Bit()); + + String string16BitFoldingToASCII = builder.toString(); + cssParserString.init(string16BitFoldingToASCII); + + ASSERT_FALSE(cssParserString.equalIgnoringASCIICase("shadow")); } TEST(CSSParserValuesTest, CSSParserValuelistClear)
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index f653367..88d4ec8 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -1534,7 +1534,7 @@ context.useCounter()->count(UseCounter::QuotedAnimationName); const CSSParserToken& token = range.consumeIncludingWhitespace(); - if (token.valueEqualsIgnoringCase("none")) + if (token.valueEqualsIgnoringASCIICase("none")) return cssValuePool().createIdentifierValue(CSSValueNone); return CSSCustomIdentValue::create(token.value()); }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp index 4a90301..deeb93b 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -576,7 +576,7 @@ return fallbackResult; range.consume(); const CSSParserToken& ident = range.consume(); - if (ident.type() != IdentToken || !ident.valueEqualsIgnoringCase("deep")) + if (ident.type() != IdentToken || !ident.valueEqualsIgnoringASCIICase("deep")) m_failedParsing = true; const CSSParserToken& slash = range.consumeIncludingWhitespace(); if (slash.type() != DelimiterToken || slash.delimiter() != '/') @@ -612,7 +612,7 @@ if (range.peek().type() != IdentToken) return CSSSelector::CaseSensitive; const CSSParserToken& flag = range.consumeIncludingWhitespace(); - if (flag.valueEqualsIgnoringCase("i")) + if (flag.valueEqualsIgnoringASCIICase("i")) return CSSSelector::CaseInsensitive; m_failedParsing = true; return CSSSelector::CaseSensitive; @@ -626,11 +626,11 @@ return true; } if (token.type() == IdentToken) { - if (token.valueEqualsIgnoringCase("odd")) { + if (token.valueEqualsIgnoringASCIICase("odd")) { result = std::make_pair(2, 1); return true; } - if (token.valueEqualsIgnoringCase("even")) { + if (token.valueEqualsIgnoringASCIICase("even")) { result = std::make_pair(2, 0); return true; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSupportsParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSupportsParser.cpp index 7764bff..56ecaf2 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSupportsParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSupportsParser.cpp
@@ -50,8 +50,8 @@ return Invalid; if (clauseType == Unresolved) clauseType = token.value().length() == 3 ? Conjunction : Disjunction; - if ((clauseType == Conjunction && !equalIgnoringCase(token.value(), "and")) - || (clauseType == Disjunction && !equalIgnoringCase(token.value(), "or"))) + if ((clauseType == Conjunction && !token.valueEqualsIgnoringASCIICase("and")) + || (clauseType == Disjunction && !token.valueEqualsIgnoringASCIICase("or"))) return Invalid; if (range.consumeIncludingWhitespace().type() != WhitespaceToken) @@ -63,7 +63,7 @@ CSSSupportsParser::SupportsResult CSSSupportsParser::consumeNegation(CSSParserTokenRange range) { ASSERT(range.peek().type() == IdentToken); - if (!equalIgnoringCase(range.consume().value(), "not")) + if (!range.consume().valueEqualsIgnoringASCIICase("not")) return Invalid; if (range.consumeIncludingWhitespace().type() != WhitespaceToken) return Invalid;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp index 31109d9e..6d4a2abd 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp
@@ -483,7 +483,7 @@ { CSSParserString name = consumeName(); if (consumeIfNext('(')) { - if (name.equalIgnoringCase("url")) { + if (name.equalIgnoringASCIICase("url")) { // The spec is slightly different so as to avoid dropping whitespace // tokens, but they wouldn't be used and this is easier. consumeUntilNonWhitespace();
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index 1d92dc9..d8847a98 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -55,16 +55,6 @@ namespace blink { -template <unsigned N> -static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N]) -{ - unsigned length = N - 1; // Ignore the trailing null character - if (a.length() != length) - return false; - - return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length); -} - void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit) { ASSERT(!isPropertyAlias(propId));
diff --git a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp index 8df06e3..cfb23db 100644 --- a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
@@ -65,19 +65,19 @@ void MediaQueryParser::readMediaNot(CSSParserTokenType type, const CSSParserToken& token) { - if (type == IdentToken && equalIgnoringCase(token.value(), "not")) + if (type == IdentToken && token.valueEqualsIgnoringASCIICase("not")) setStateAndRestrict(ReadFeatureStart, MediaQuery::Not); else readFeatureStart(type, token); } -static bool isRestrictorOrLogicalOperator(const String& tokenValue) +static bool isRestrictorOrLogicalOperator(const CSSParserToken& token) { // FIXME: it would be more efficient to use lower-case always for tokenValue. - return equalIgnoringCase(tokenValue, "not") - || equalIgnoringCase(tokenValue, "and") - || equalIgnoringCase(tokenValue, "or") - || equalIgnoringCase(tokenValue, "only"); + return token.valueEqualsIgnoringASCIICase("not") + || token.valueEqualsIgnoringASCIICase("and") + || token.valueEqualsIgnoringASCIICase("or") + || token.valueEqualsIgnoringASCIICase("only"); } void MediaQueryParser::readMediaType(CSSParserTokenType type, const CSSParserToken& token) @@ -88,12 +88,12 @@ else m_state = ReadFeature; } else if (type == IdentToken) { - if (m_state == ReadRestrictor && equalIgnoringCase(token.value(), "not")) { + if (m_state == ReadRestrictor && token.valueEqualsIgnoringASCIICase("not")) { setStateAndRestrict(ReadMediaType, MediaQuery::Not); - } else if (m_state == ReadRestrictor && equalIgnoringCase(token.value(), "only")) { + } else if (m_state == ReadRestrictor && token.valueEqualsIgnoringASCIICase("only")) { setStateAndRestrict(ReadMediaType, MediaQuery::Only); } else if (m_mediaQueryData.restrictor() != MediaQuery::None - && isRestrictorOrLogicalOperator(token.value())) { + && isRestrictorOrLogicalOperator(token)) { m_state = SkipUntilComma; } else { m_mediaQueryData.setMediaType(token.value()); @@ -110,7 +110,7 @@ void MediaQueryParser::readAnd(CSSParserTokenType type, const CSSParserToken& token) { - if (type == IdentToken && equalIgnoringCase(token.value(), "and")) { + if (type == IdentToken && token.valueEqualsIgnoringASCIICase("and")) { m_state = ReadFeatureStart; } else if (type == CommaToken && m_parserType != MediaConditionParser) { m_querySet->addMediaQuery(m_mediaQueryData.takeMediaQuery());
diff --git a/third_party/WebKit/Source/core/css/parser/SizesCalcParser.cpp b/third_party/WebKit/Source/core/css/parser/SizesCalcParser.cpp index 4dd16c9a..889607d 100644 --- a/third_party/WebKit/Source/core/css/parser/SizesCalcParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/SizesCalcParser.cpp
@@ -105,7 +105,7 @@ return false; break; case FunctionToken: - if (!token.valueEqualsIgnoringCase("calc")) + if (!token.valueEqualsIgnoringASCIICase("calc")) return false; // "calc(" is the same as "(" case LeftParenthesisToken:
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp index 33a2833..ecb5e43 100644 --- a/third_party/WebKit/Source/core/fetch/Resource.cpp +++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -1115,6 +1115,8 @@ return "XSL stylesheet"; case Resource::LinkPrefetch: return "Link prefetch resource"; + case Resource::LinkPreload: + return "Link preload resource"; case Resource::LinkSubresource: return "Link subresource"; case Resource::TextTrack: @@ -1149,6 +1151,7 @@ return true; case Resource::Raw: case Resource::LinkPrefetch: + case Resource::LinkPreload: case Resource::LinkSubresource: case Resource::TextTrack: case Resource::Media: @@ -1182,6 +1185,8 @@ return "XSLStyleSheet"; case Resource::LinkPrefetch: return "LinkPrefetch"; + case Resource::LinkPreload: + return "LinkPreload"; case Resource::LinkSubresource: return "LinkSubresource"; case Resource::TextTrack:
diff --git a/third_party/WebKit/Source/core/fetch/Resource.h b/third_party/WebKit/Source/core/fetch/Resource.h index 094129053..33c12f1 100644 --- a/third_party/WebKit/Source/core/fetch/Resource.h +++ b/third_party/WebKit/Source/core/fetch/Resource.h
@@ -77,6 +77,7 @@ XSLStyleSheet, LinkPrefetch, LinkSubresource, + LinkPreload, TextTrack, ImportResource, Media, // Audio or video file requested by a HTML5 media element @@ -125,7 +126,6 @@ virtual bool shouldIgnoreHTTPStatusCodeErrors() const { return false; } - ResourceRequest& mutableResourceRequest() { return m_resourceRequest; } const ResourceRequest& resourceRequest() const { return m_resourceRequest; } const ResourceRequest& lastResourceRequest() const;
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp index 36307ed3..08cf67e 100644 --- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp +++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -89,6 +89,7 @@ case Resource::Manifest: return ResourceLoadPriorityMedium; case Resource::LinkSubresource: + case Resource::LinkPreload: case Resource::TextTrack: case Resource::Media: case Resource::SVGDocument: @@ -151,6 +152,8 @@ return WebURLRequest::RequestContextImport; case Resource::LinkPrefetch: return WebURLRequest::RequestContextPrefetch; + case Resource::LinkPreload: + return WebURLRequest::RequestContextSubresource; case Resource::LinkSubresource: return WebURLRequest::RequestContextSubresource; case Resource::TextTrack:
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/third_party/WebKit/Source/core/frame/DOMWindow.cpp index df0dd0e..8442461f 100644 --- a/third_party/WebKit/Source/core/frame/DOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
@@ -203,8 +203,6 @@ String sourceOrigin = sourceDocument->securityOrigin()->toString(); String sourceSuborigin = sourceDocument->securityOrigin()->suboriginName(); - // FIXME: MixedContentChecker needs to be refactored for OOPIF. For now, - // create the url using replicated origins for remote frames. KURL targetUrl = isLocalDOMWindow() ? document()->url() : KURL(KURL(), frame()->securityContext()->securityOrigin()->toString()); if (MixedContentChecker::isMixedContent(sourceDocument->securityOrigin(), targetUrl)) UseCounter::count(frame(), UseCounter::PostMessageFromSecureToInsecure);
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index f94c98e..a6304a7 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -3727,16 +3727,11 @@ void FrameView::paint(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const CullRect& cullRect) const { - // TODO(skyostil): Remove this early-out in favor of painting cached scrollbars. - if (shouldThrottleRendering()) - return; FramePainter(*this).paint(context, globalPaintFlags, cullRect); } void FrameView::paintContents(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const IntRect& damageRect) const { - if (shouldThrottleRendering()) - return; FramePainter(*this).paintContents(context, globalPaintFlags, damageRect); } @@ -4032,8 +4027,15 @@ } bool becameUnthrottled = wasThrottled && !canThrottleRendering(); - if (becameUnthrottled) + if (becameUnthrottled) { + // Start ticking animation frames again if necessary. page()->animator().scheduleVisualUpdate(m_frame.get()); + // Force a full repaint of this frame to ensure we are not left with a + // partially painted version of this frame's contents if we skipped + // painting them while the frame was throttled. + if (LayoutView* layoutView = this->layoutView()) + layoutView->setShouldDoFullPaintInvalidation(PaintInvalidationBecameVisible); + } } bool FrameView::shouldThrottleRendering() const
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp index d119619..bb4e23a9 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -365,7 +365,7 @@ TEST_F(HTMLPreloadScannerTest, testLinkRelPreload) { TestCase testCases[] = { - {"http://example.test", "<link rel=preload href=bla>", "bla", "http://example.test/", Resource::LinkSubresource, 0}, + {"http://example.test", "<link rel=preload href=bla>", "bla", "http://example.test/", Resource::LinkPreload, 0}, {"http://example.test", "<link rel=preload href=bla as=script>", "bla", "http://example.test/", Resource::Script, 0}, {"http://example.test", "<link rel=preload href=bla as=style>", "bla", "http://example.test/", Resource::CSSStyleSheet, 0}, {"http://example.test", "<link rel=preload href=bla as=image>", "bla", "http://example.test/", Resource::Image, 0},
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index b0cb299..65fcc59 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2679,7 +2679,7 @@ LayoutUnit LayoutBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const { - LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().hasPercent()) || style()->logicalMinWidth().isMaxSizeNone() ? logicalWidth : computeReplacedLogicalWidthUsing(MinSize, style()->logicalMinWidth()); + LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().hasPercent()) ? logicalWidth : computeReplacedLogicalWidthUsing(MinSize, style()->logicalMinWidth()); LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().hasPercent()) || style()->logicalMaxWidth().isMaxSizeNone() ? logicalWidth : computeReplacedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth()); return std::max(minLogicalWidth, std::min(logicalWidth, maxLogicalWidth)); }
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp index e33f8df5..d337666 100644 --- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -187,7 +187,7 @@ case Resource::ImportResource: resource = RawResource::fetchImport(request, fetcher()); break; - case Resource::LinkSubresource: + case Resource::LinkPreload: resource = RawResource::fetch(request, fetcher()); break; default:
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 27d73c6..000e8f9 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -428,6 +428,7 @@ case Resource::Font: case Resource::Raw: case Resource::LinkPrefetch: + case Resource::LinkPreload: case Resource::LinkSubresource: case Resource::TextTrack: case Resource::ImportResource: @@ -505,6 +506,11 @@ return ResourceRequestBlockedReasonCSP; break; } + case Resource::LinkPreload: + ASSERT(csp); + if (!shouldBypassMainWorldCSP && !csp->allowConnectToSource(url, redirectStatus, cspReporting)) + return ResourceRequestBlockedReasonCSP; + break; case Resource::MainResource: case Resource::Raw: case Resource::LinkPrefetch: @@ -559,7 +565,7 @@ // They'll still get a warning in the console about CSP blocking the load. MixedContentChecker::ReportingStatus mixedContentReporting = forPreload ? MixedContentChecker::SuppressReport : MixedContentChecker::SendReport; - if (MixedContentChecker::shouldBlockFetch(MixedContentChecker::effectiveFrameForFrameType(frame(), resourceRequest.frameType()), resourceRequest, url, mixedContentReporting)) + if (MixedContentChecker::shouldBlockFetch(frame(), resourceRequest, url, mixedContentReporting)) return ResourceRequestBlockedReasonMixedContent; return ResourceRequestBlockedReasonNone;
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp index 05fd8bc..e0f24c16 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp +++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -184,8 +184,7 @@ return Resource::TextTrack; if (document && !as.isEmpty()) document->addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> must have a valid `as` value"))); - // TODO(yoav): Is this correct? If as is missing or invalid, it should be subject to "connect-src" CSP directives. - return Resource::LinkSubresource; + return Resource::LinkPreload; } void LinkLoader::createLinkPreloadResourceClient(ResourcePtr<Resource> resource)
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp index 0b0dd21..a1bad4b 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp +++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -29,6 +29,7 @@ #include "core/loader/MixedContentChecker.h" #include "core/dom/Document.h" +#include "core/frame/Frame.h" #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" #include "core/frame/UseCounter.h" @@ -44,22 +45,37 @@ namespace blink { -static void measureStricterVersionOfIsMixedContent(LocalFrame* frame, const KURL& url) +namespace { + +// When a frame is local, use its full URL to represent the main +// resource. When the frame is remote, the full URL isn't accessible, so +// use the origin. This function is used, for example, to determine the +// URL to show in console messages about mixed content. +KURL mainResourceUrlForFrame(Frame* frame) +{ + if (frame->isRemoteFrame()) + return KURL(KURL(), frame->securityContext()->securityOrigin()->toString()); + return toLocalFrame(frame)->document()->url(); +} + +} // namespace + +static void measureStricterVersionOfIsMixedContent(Frame* frame, const KURL& url) { // We're currently only checking for mixed content in `https://*` contexts. // What about other "secure" contexts the SchemeRegistry knows about? We'll // use this method to measure the occurance of non-webby mixed content to // make sure we're not breaking the world without realizing it. - SecurityOrigin* origin = frame->document()->securityOrigin(); + SecurityOrigin* origin = frame->securityContext()->securityOrigin(); if (MixedContentChecker::isMixedContent(origin, url)) { - if (frame->document()->securityOrigin()->protocol() != "https") + if (origin->protocol() != "https") UseCounter::count(frame, UseCounter::MixedContentInNonHTTPSFrameThatRestrictsMixedContent); } else if (!SecurityOrigin::isSecure(url) && SchemeRegistry::shouldTreatURLSchemeAsSecure(origin->protocol())) { UseCounter::count(frame, UseCounter::MixedContentInSecureFrameThatDoesNotRestrictMixedContent); } } -bool requestIsSubframeSubresource(LocalFrame* frame, WebURLRequest::FrameType frameType) +bool requestIsSubframeSubresource(Frame* frame, WebURLRequest::FrameType frameType) { return (frame && frame != frame->tree().top() && frameType != WebURLRequest::FrameTypeNested); } @@ -75,7 +91,7 @@ } // static -LocalFrame* MixedContentChecker::inWhichFrameIsContentMixed(LocalFrame* frame, WebURLRequest::FrameType frameType, const KURL& url) +Frame* MixedContentChecker::inWhichFrameIsContentMixed(Frame* frame, WebURLRequest::FrameType frameType, const KURL& url) { // We only care about subresource loads; top-level navigations cannot be mixed content. Neither can frameless requests. if (frameType == WebURLRequest::FrameTypeTopLevel || !frame) @@ -83,19 +99,13 @@ // Check the top frame first. if (Frame* top = frame->tree().top()) { - // FIXME: We need a way to access the top-level frame's SecurityOrigin when that frame - // is in a different process from the current frame. Until that is done, we bail out. - if (!top->isLocalFrame()) - return nullptr; - - LocalFrame* localTop = toLocalFrame(top); - measureStricterVersionOfIsMixedContent(localTop, url); - if (isMixedContent(localTop->document()->securityOrigin(), url)) - return localTop; + measureStricterVersionOfIsMixedContent(top, url); + if (isMixedContent(top->securityContext()->securityOrigin(), url)) + return top; } measureStricterVersionOfIsMixedContent(frame, url); - if (isMixedContent(frame->document()->securityOrigin(), url)) + if (isMixedContent(frame->securityContext()->securityOrigin(), url)) return frame; // No mixed content, no problem. @@ -103,7 +113,7 @@ } // static -MixedContentChecker::ContextType MixedContentChecker::contextTypeFromContext(WebURLRequest::RequestContext context, LocalFrame* frame) +MixedContentChecker::ContextType MixedContentChecker::contextTypeFromContext(WebURLRequest::RequestContext context, Frame* frame) { switch (context) { // "Optionally-blockable" mixed content @@ -238,18 +248,18 @@ } // static -void MixedContentChecker::logToConsoleAboutFetch(LocalFrame* frame, const KURL& url, WebURLRequest::RequestContext requestContext, bool allowed) +void MixedContentChecker::logToConsoleAboutFetch(LocalFrame* frame, const KURL& mainResourceUrl, const KURL& url, WebURLRequest::RequestContext requestContext, bool allowed) { String message = String::format( "Mixed Content: The page at '%s' was loaded over HTTPS, but requested an insecure %s '%s'. %s", - frame->document()->url().elidedString().utf8().data(), typeNameFromContext(requestContext), url.elidedString().utf8().data(), + mainResourceUrl.elidedString().utf8().data(), typeNameFromContext(requestContext), url.elidedString().utf8().data(), allowed ? "This content should also be served over HTTPS." : "This request has been blocked; the content must be served over HTTPS."); MessageLevel messageLevel = allowed ? WarningMessageLevel : ErrorMessageLevel; frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, messageLevel, message)); } // static -void MixedContentChecker::count(LocalFrame* frame, WebURLRequest::RequestContext requestContext) +void MixedContentChecker::count(Frame* frame, WebURLRequest::RequestContext requestContext) { UseCounter::count(frame, UseCounter::MixedContentPresent); @@ -298,15 +308,19 @@ // static bool MixedContentChecker::shouldBlockFetch(LocalFrame* frame, WebURLRequest::RequestContext requestContext, WebURLRequest::FrameType frameType, const KURL& url, MixedContentChecker::ReportingStatus reportingStatus) { - LocalFrame* mixedFrame = inWhichFrameIsContentMixed(frame, frameType, url); + Frame* effectiveFrame = effectiveFrameForFrameType(frame, frameType); + Frame* mixedFrame = inWhichFrameIsContentMixed(effectiveFrame, frameType, url); if (!mixedFrame) return false; MixedContentChecker::count(mixedFrame, requestContext); Settings* settings = mixedFrame->settings(); - FrameLoaderClient* client = mixedFrame->loader().client(); - SecurityOrigin* securityOrigin = mixedFrame->document()->securityOrigin(); + // Use the current local frame's client; the embedder doesn't + // distinguish mixed content signals from different frames on the + // same page. + FrameLoaderClient* client = frame->loader().client(); + SecurityOrigin* securityOrigin = mixedFrame->securityContext()->securityOrigin(); bool allowed = false; // If we're in strict mode, we'll automagically fail everything, and intentionally skip @@ -334,7 +348,7 @@ case ContextTypeBlockable: { // Strictly block subresources in subframes, unless all insecure // content is allowed. - if (!settings->allowRunningOfInsecureContent() && requestIsSubframeSubresource(frame, frameType)) { + if (!settings->allowRunningOfInsecureContent() && requestIsSubframeSubresource(effectiveFrame, frameType)) { UseCounter::count(mixedFrame, UseCounter::BlockableMixedContentInSubframeBlocked); allowed = false; break; @@ -360,16 +374,16 @@ }; if (reportingStatus == SendReport) - logToConsoleAboutFetch(frame, url, requestContext, allowed); + logToConsoleAboutFetch(frame, mainResourceUrlForFrame(mixedFrame), url, requestContext, allowed); return !allowed; } // static -void MixedContentChecker::logToConsoleAboutWebSocket(LocalFrame* frame, const KURL& url, bool allowed) +void MixedContentChecker::logToConsoleAboutWebSocket(LocalFrame* frame, const KURL& mainResourceUrl, const KURL& url, bool allowed) { String message = String::format( "Mixed Content: The page at '%s' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint '%s'. %s", - frame->document()->url().elidedString().utf8().data(), url.elidedString().utf8().data(), + mainResourceUrl.elidedString().utf8().data(), url.elidedString().utf8().data(), allowed ? "This endpoint should be available via WSS. Insecure access is deprecated." : "This request has been blocked; this endpoint must be available over WSS."); MessageLevel messageLevel = allowed ? WarningMessageLevel : ErrorMessageLevel; frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, messageLevel, message)); @@ -378,7 +392,7 @@ // static bool MixedContentChecker::shouldBlockWebSocket(LocalFrame* frame, const KURL& url, MixedContentChecker::ReportingStatus reportingStatus) { - LocalFrame* mixedFrame = inWhichFrameIsContentMixed(frame, WebURLRequest::FrameTypeNone, url); + Frame* mixedFrame = inWhichFrameIsContentMixed(frame, WebURLRequest::FrameTypeNone, url); if (!mixedFrame) return false; @@ -386,13 +400,16 @@ UseCounter::count(mixedFrame, UseCounter::MixedContentWebSocket); Settings* settings = mixedFrame->settings(); - FrameLoaderClient* client = mixedFrame->loader().client(); - SecurityOrigin* securityOrigin = mixedFrame->document()->securityOrigin(); + // Use the current local frame's client; the embedder doesn't + // distinguish mixed content signals from different frames on the + // same page. + FrameLoaderClient* client = frame->loader().client(); + SecurityOrigin* securityOrigin = mixedFrame->securityContext()->securityOrigin(); bool allowed = false; // If we're in strict mode, we'll automagically fail everything, and intentionally skip // the client checks in order to prevent degrading the site's security UI. - bool strictMode = mixedFrame->document()->shouldEnforceStrictMixedContentChecking() || settings->strictMixedContentChecking(); + bool strictMode = mixedFrame->securityContext()->shouldEnforceStrictMixedContentChecking() || settings->strictMixedContentChecking(); if (!strictMode) { bool allowedPerSettings = settings && settings->allowRunningOfInsecureContent(); allowed = client->allowRunningInsecureContent(allowedPerSettings, securityOrigin, url); @@ -402,7 +419,7 @@ client->didRunInsecureContent(securityOrigin, url); if (reportingStatus == SendReport) - logToConsoleAboutWebSocket(frame, url, allowed); + logToConsoleAboutWebSocket(frame, mainResourceUrlForFrame(mixedFrame), url, allowed); return !allowed; } @@ -414,19 +431,22 @@ if (url.protocolIs("javascript")) return false; - LocalFrame* mixedFrame = inWhichFrameIsContentMixed(frame, WebURLRequest::FrameTypeNone, url); + Frame* mixedFrame = inWhichFrameIsContentMixed(frame, WebURLRequest::FrameTypeNone, url); if (!mixedFrame) return false; UseCounter::count(mixedFrame, UseCounter::MixedContentPresent); - mixedFrame->loader().client()->didDisplayInsecureContent(); + // Use the current local frame's client; the embedder doesn't + // distinguish mixed content signals from different frames on the + // same page. + frame->loader().client()->didDisplayInsecureContent(); if (reportingStatus == SendReport) { String message = String::format( "Mixed Content: The page at '%s' was loaded over a secure connection, but contains a form which targets an insecure endpoint '%s'. This endpoint should be made available over a secure connection.", - frame->document()->url().elidedString().utf8().data(), url.elidedString().utf8().data()); - mixedFrame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, WarningMessageLevel, message)); + mainResourceUrlForFrame(mixedFrame).elidedString().utf8().data(), url.elidedString().utf8().data()); + frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, WarningMessageLevel, message)); } return true; @@ -442,47 +462,53 @@ UseCounter::count(frame->document(), UseCounter::MixedContentPrivateHostnameInPublicHostname); } -LocalFrame* MixedContentChecker::effectiveFrameForFrameType(LocalFrame* frame, WebURLRequest::FrameType frameType) +Frame* MixedContentChecker::effectiveFrameForFrameType(LocalFrame* frame, WebURLRequest::FrameType frameType) { // If we're loading the main resource of a subframe, ensure that we check // against the parent of the active frame, rather than the frame itself. - LocalFrame* effectiveFrame = frame; - if (frameType == WebURLRequest::FrameTypeNested) { - // FIXME: Deal with RemoteFrames. - Frame* parentFrame = effectiveFrame->tree().parent(); - ASSERT(parentFrame); - if (parentFrame->isLocalFrame()) - effectiveFrame = toLocalFrame(parentFrame); - } - return effectiveFrame; + if (frameType != WebURLRequest::FrameTypeNested) + return frame; + + Frame* parentFrame = frame->tree().parent(); + ASSERT(parentFrame); + return parentFrame; } void MixedContentChecker::handleCertificateError(LocalFrame* frame, const ResourceRequest& request, const ResourceResponse& response) { WebURLRequest::FrameType frameType = request.frameType(); - LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, frameType); + Frame* effectiveFrame = effectiveFrameForFrameType(frame, frameType); if (frameType == WebURLRequest::FrameTypeTopLevel || !effectiveFrame) return; - FrameLoaderClient* client = effectiveFrame->loader().client(); + // TODO(estark): handle remote frames, perhaps by omitting security info when the effective frame is remote. + if (!effectiveFrame->isLocalFrame()) + return; + + LocalFrame* localEffectiveFrame = toLocalFrame(effectiveFrame); + + // Use the current local frame's client; the embedder doesn't + // distinguish mixed content signals from different frames on the + // same page. + FrameLoaderClient* client = frame->loader().client(); WebURLRequest::RequestContext requestContext = request.requestContext(); - ContextType contextType = MixedContentChecker::contextTypeFromContext(requestContext, frame); + ContextType contextType = MixedContentChecker::contextTypeFromContext(requestContext, effectiveFrame); if (contextType == ContextTypeBlockable) { - client->didRunContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo()); + client->didRunContentWithCertificateErrors(response.url(), response.getSecurityInfo(), mainResourceUrlForFrame(effectiveFrame), localEffectiveFrame->loader().documentLoader()->response().getSecurityInfo()); } else { // contextTypeFromContext() never returns NotMixedContent (it // computes the type of mixed content, given that the content is // mixed). ASSERT(contextType != ContextTypeNotMixedContent); - client->didDisplayContentWithCertificateErrors(response.url(), response.getSecurityInfo(), effectiveFrame->document()->url(), effectiveFrame->loader().documentLoader()->response().getSecurityInfo()); + client->didDisplayContentWithCertificateErrors(response.url(), response.getSecurityInfo(), mainResourceUrlForFrame(effectiveFrame), localEffectiveFrame->loader().documentLoader()->response().getSecurityInfo()); } } MixedContentChecker::ContextType MixedContentChecker::contextTypeForInspector(LocalFrame* frame, const ResourceRequest& request) { - LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType()); + Frame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType()); - LocalFrame* mixedFrame = inWhichFrameIsContentMixed(effectiveFrame, request.frameType(), request.url()); + Frame* mixedFrame = inWhichFrameIsContentMixed(effectiveFrame, request.frameType(), request.url()); if (!mixedFrame) return ContextTypeNotMixedContent;
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.h b/third_party/WebKit/Source/core/loader/MixedContentChecker.h index e2e50c4..a12196f 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentChecker.h +++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.h
@@ -40,6 +40,7 @@ namespace blink { +class Frame; class FrameLoaderClient; class LocalFrame; class KURL; @@ -75,7 +76,7 @@ // Returns the frame that should be considered the effective frame // for a mixed content check for the given frame type. - static LocalFrame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType); + static Frame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType); static void handleCertificateError(LocalFrame*, const ResourceRequest&, const ResourceResponse&); @@ -88,13 +89,13 @@ Submission }; - static LocalFrame* inWhichFrameIsContentMixed(LocalFrame*, WebURLRequest::FrameType, const KURL&); + static Frame* inWhichFrameIsContentMixed(Frame*, WebURLRequest::FrameType, const KURL&); - static ContextType contextTypeFromContext(WebURLRequest::RequestContext, LocalFrame*); + static ContextType contextTypeFromContext(WebURLRequest::RequestContext, Frame*); static const char* typeNameFromContext(WebURLRequest::RequestContext); - static void logToConsoleAboutFetch(LocalFrame*, const KURL&, WebURLRequest::RequestContext, bool allowed); - static void logToConsoleAboutWebSocket(LocalFrame*, const KURL&, bool allowed); - static void count(LocalFrame*, WebURLRequest::RequestContext); + static void logToConsoleAboutFetch(LocalFrame*, const KURL&, const KURL&, WebURLRequest::RequestContext, bool allowed); + static void logToConsoleAboutWebSocket(LocalFrame*, const KURL&, const KURL&, bool allowed); + static void count(Frame*, WebURLRequest::RequestContext); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/FramePainter.cpp b/third_party/WebKit/Source/core/paint/FramePainter.cpp index a6eb08c9..ba89543c 100644 --- a/third_party/WebKit/Source/core/paint/FramePainter.cpp +++ b/third_party/WebKit/Source/core/paint/FramePainter.cpp
@@ -111,8 +111,10 @@ return; } - RELEASE_ASSERT(!frameView().needsLayout()); - ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); + if (!frameView().shouldThrottleRendering()) { + RELEASE_ASSERT(!frameView().needsLayout()); + ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); + } TRACE_EVENT1("devtools.timeline", "Paint", "data", InspectorPaintEvent::data(layoutView, LayoutRect(rect), 0)); @@ -133,7 +135,8 @@ PaintLayer* rootLayer = layoutView->layer(); #if ENABLE(ASSERT) - layoutView->assertSubtreeIsLaidOut(); + if (!frameView().shouldThrottleRendering()) + layoutView->assertSubtreeIsLaidOut(); LayoutObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->layoutObject()); #endif
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp index 31bbc5ce..4eea6f7 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -4,6 +4,7 @@ #include "core/paint/PaintLayerPainter.h" +#include "core/frame/FrameView.h" #include "core/frame/Settings.h" #include "core/layout/ClipPathOperation.h" #include "core/layout/LayoutBlock.h" @@ -80,8 +81,7 @@ if (shouldSuppressPaintingLayer(&m_paintLayer)) return FullyPainted; - // TODO(skyostil): Unify this early-out logic with subsequence caching. - if (m_paintLayer.layoutObject()->isLayoutPart() && toLayoutPart(m_paintLayer.layoutObject())->isThrottledFrameView()) + if (m_paintLayer.layoutObject()->isLayoutView() && toLayoutView(m_paintLayer.layoutObject())->frameView()->shouldThrottleRendering()) return FullyPainted; // If this layer is totally invisible then there is nothing to paint. @@ -270,9 +270,8 @@ if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !m_paintLayer.layoutObject()->isLayoutView() && !m_paintLayer.layoutObject()->isDocumentElement()) return result; - // TODO(skyostil): Unify this early-out logic with subsequence caching. - if (m_paintLayer.layoutObject()->isLayoutPart() && toLayoutPart(m_paintLayer.layoutObject())->isThrottledFrameView()) - return FullyPainted; + if (m_paintLayer.layoutObject()->isLayoutView() && toLayoutView(m_paintLayer.layoutObject())->frameView()->shouldThrottleRendering()) + return result; // Ensure our lists are up-to-date. m_paintLayer.stackingNode()->updateLayerListsIfNeeded();
diff --git a/third_party/WebKit/Source/core/svg/SVGPathParser.cpp b/third_party/WebKit/Source/core/svg/SVGPathParser.cpp index e688918..7a1b5c3 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathParser.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPathParser.cpp
@@ -297,18 +297,4 @@ return true; } -bool SVGPathParser::parseAndNormalizePath() -{ - SVGPathNormalizer normalizer(m_consumer); - - while (m_source->hasMoreData()) { - PathSegmentData segment = m_source->parseSegment(); - if (segment.command == PathSegUnknown) - return false; - - normalizer.emitSegment(segment); - } - return true; -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGPathParser.h b/third_party/WebKit/Source/core/svg/SVGPathParser.h index f5f78d2..9274586 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathParser.h +++ b/third_party/WebKit/Source/core/svg/SVGPathParser.h
@@ -30,11 +30,6 @@ namespace blink { -enum PathParsingMode { - NormalizedParsing, - UnalteredParsing -}; - class SVGPathConsumer; class SVGPathSource; @@ -50,21 +45,18 @@ ASSERT(m_consumer); } - bool parsePathDataFromSource(PathParsingMode pathParsingMode, bool checkForInitialMoveTo = true) + bool parsePathDataFromSource(bool checkForInitialMoveTo = true) { ASSERT(m_source); ASSERT(m_consumer); if (checkForInitialMoveTo && !initialCommandIsMoveTo()) return false; - if (pathParsingMode == NormalizedParsing) - return parseAndNormalizePath(); return parsePath(); } private: bool initialCommandIsMoveTo(); bool parsePath(); - bool parseAndNormalizePath(); SVGPathSource* m_source; SVGPathConsumer* m_consumer;
diff --git a/third_party/WebKit/Source/core/svg/SVGPathParserTest.cpp b/third_party/WebKit/Source/core/svg/SVGPathParserTest.cpp index b81b52047..8cfa4de 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathParserTest.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPathParserTest.cpp
@@ -18,7 +18,7 @@ SVGPathStringSource source(inputString); SVGPathStringBuilder builder; SVGPathParser parser(&source, &builder); - bool hadError = parser.parsePathDataFromSource(UnalteredParsing, true); + bool hadError = parser.parsePathDataFromSource(); output = builder.result(); // Coerce a null result to empty. if (output.isNull())
diff --git a/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp b/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp index 259bf0e..1fde0eb 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp
@@ -36,7 +36,7 @@ SVGPathBuilder builder(result); SVGPathStringSource source(d); SVGPathParser parser(&source, &builder); - return parser.parsePathDataFromSource(UnalteredParsing); + return parser.parsePathDataFromSource(); } bool buildPathFromByteStream(const SVGPathByteStream& stream, Path& result) @@ -47,7 +47,7 @@ SVGPathBuilder builder(result); SVGPathByteStreamSource source(stream); SVGPathParser parser(&source, &builder); - return parser.parsePathDataFromSource(UnalteredParsing); + return parser.parsePathDataFromSource(); } String buildStringFromByteStream(const SVGPathByteStream& stream) @@ -58,7 +58,7 @@ SVGPathStringBuilder builder; SVGPathByteStreamSource source(stream); SVGPathParser parser(&source, &builder); - parser.parsePathDataFromSource(UnalteredParsing); + parser.parsePathDataFromSource(); return builder.result(); } @@ -74,7 +74,7 @@ SVGPathByteStreamBuilder builder(result); SVGPathStringSource source(d); SVGPathParser parser(&source, &builder); - bool ok = parser.parsePathDataFromSource(UnalteredParsing); + bool ok = parser.parsePathDataFromSource(); result.shrinkToFit(); return ok; }
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.cpp index c654111..cb7957d 100644 --- a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.cpp +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.cpp
@@ -27,6 +27,11 @@ namespace blink { +bool SVGImageForContainer::isTextureBacked() +{ + return m_image->isTextureBacked(); +} + IntSize SVGImageForContainer::size() const { FloatSize scaledContainerSize(m_containerSize);
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h index ba6c83d7..08dfd5b 100644 --- a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h
@@ -44,6 +44,7 @@ return adoptRef(new SVGImageForContainer(image, containerSizeWithoutZoom, zoom, url)); } + bool isTextureBacked() override; IntSize size() const override; bool usesContainerSize() const override { return m_image->usesContainerSize(); }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp index 9277df92..a0f825c0 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
@@ -8,7 +8,9 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromiseResolver.h" #include "core/dom/DOMException.h" +#include "core/dom/Document.h" #include "core/dom/ExceptionCode.h" +#include "core/page/PageVisibilityState.h" #include "modules/bluetooth/BluetoothError.h" #include "modules/bluetooth/BluetoothGATTRemoteServer.h" #include "modules/bluetooth/BluetoothSupplement.h" @@ -79,6 +81,13 @@ ScriptPromise BluetoothDevice::connectGATT(ScriptState* scriptState) { + // TODO(ortuno): Allow connections when the tab is in the background. + // This is a short term solution instead of implementing a tab indicator + // for bluetooth connections. + // https://crbug.com/579746 + if (!toDocument(scriptState->executionContext())->page()->isPageVisible()) { + return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(SecurityError, "Connection is only allowed while the page is visible. This is a temporary measure until we are able to effectively communicate to the user that a page is connected to a device.")); + } WebBluetooth* webbluetooth = BluetoothSupplement::fromScriptState(scriptState); if (!webbluetooth) return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp index 862d9031..a6f0956 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp
@@ -8,6 +8,7 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromiseResolver.h" #include "core/dom/DOMException.h" +#include "core/dom/Document.h" #include "core/dom/ExceptionCode.h" #include "modules/bluetooth/BluetoothError.h" #include "modules/bluetooth/BluetoothGATTService.h" @@ -18,15 +19,56 @@ namespace blink { -BluetoothGATTRemoteServer::BluetoothGATTRemoteServer(PassOwnPtr<WebBluetoothGATTRemoteServer> webGATT) - : m_webGATT(webGATT) +BluetoothGATTRemoteServer::BluetoothGATTRemoteServer(ExecutionContext* context, PassOwnPtr<WebBluetoothGATTRemoteServer> webGATT) + : ActiveDOMObject(context) + , PageLifecycleObserver(toDocument(context)->page()) + , m_webGATT(webGATT) { + // See example in Source/platform/heap/ThreadState.h + ThreadState::current()->registerPreFinalizer(this); } -BluetoothGATTRemoteServer* BluetoothGATTRemoteServer::take(ScriptPromiseResolver*, PassOwnPtr<WebBluetoothGATTRemoteServer> webGATT) +BluetoothGATTRemoteServer* BluetoothGATTRemoteServer::take(ScriptPromiseResolver* resolver, PassOwnPtr<WebBluetoothGATTRemoteServer> webGATT) { ASSERT(webGATT); - return new BluetoothGATTRemoteServer(webGATT); + BluetoothGATTRemoteServer* server = new BluetoothGATTRemoteServer(resolver->executionContext(), webGATT); + if (!server->page()->isPageVisible()) { + server->disconnectIfConnected(); + } + server->suspendIfNeeded(); + return server; +} + +void BluetoothGATTRemoteServer::dispose() +{ + disconnectIfConnected(); +} + +void BluetoothGATTRemoteServer::stop() +{ + disconnectIfConnected(); +} + +void BluetoothGATTRemoteServer::pageVisibilityChanged() +{ + if (!page()->isPageVisible()) { + disconnectIfConnected(); + } +} + +void BluetoothGATTRemoteServer::disconnectIfConnected() +{ + if (m_webGATT->connected) { + m_webGATT->connected = false; + WebBluetooth* webbluetooth = BluetoothSupplement::fromExecutionContext(executionContext()); + webbluetooth->disconnect(m_webGATT->deviceId); + } +} + +DEFINE_TRACE(BluetoothGATTRemoteServer) +{ + ActiveDOMObject::trace(visitor); + PageLifecycleObserver::trace(visitor); } void BluetoothGATTRemoteServer::disconnect(ScriptState* scriptState)
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h index 5cad459..87e65040 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h
@@ -7,6 +7,8 @@ #include "bindings/core/v8/ScriptWrappable.h" #include "bindings/modules/v8/UnionTypesModules.h" +#include "core/dom/ActiveDOMObject.h" +#include "core/page/PageLifecycleObserver.h" #include "platform/heap/Heap.h" #include "public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h" #include "wtf/OwnPtr.h" @@ -27,17 +29,48 @@ // CallbackPromiseAdapter class comments. class BluetoothGATTRemoteServer final : public GarbageCollectedFinalized<BluetoothGATTRemoteServer> + , public ActiveDOMObject + , public PageLifecycleObserver , public ScriptWrappable { + USING_PRE_FINALIZER(BluetoothGATTRemoteServer, dispose); DEFINE_WRAPPERTYPEINFO(); + WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(BluetoothGATTRemoteServer); public: - BluetoothGATTRemoteServer(PassOwnPtr<WebBluetoothGATTRemoteServer>); + BluetoothGATTRemoteServer(ExecutionContext*, PassOwnPtr<WebBluetoothGATTRemoteServer>); // Interface required by CallbackPromiseAdapter: using WebType = OwnPtr<WebBluetoothGATTRemoteServer>; static BluetoothGATTRemoteServer* take(ScriptPromiseResolver*, PassOwnPtr<WebBluetoothGATTRemoteServer>); + // We should disconnect from the device in all of the following cases: + // 1. When the object gets GarbageCollected e.g. it went out of scope. + // dispose() is called in this case. + // 2. When the parent document gets detached e.g. reloading a page. + // stop() is called in this case. + // 3. For now (https://crbug.com/579746), when the tab is no longer in the + // foreground e.g. change tabs. + // pageVisibilityChanged() is called in this case. + // TODO(ortuno): Users should be able to turn on notifications listen for + // events on navigator.bluetooth and still remain connected even if the + // BluetoothGATTRemoteServer object is garbage collected. + // TODO(ortuno): Allow connections when the tab is in the background. + // This is a short term solution instead of implementing a tab indicator + // for bluetooth connections. + + // USING_PRE_FINALIZER interface. + // Called before the object gets garbage collected. + void dispose(); + + // ActiveDOMObject interface. + void stop() override; + + // PageLifecycleObserver interface. + void pageVisibilityChanged() override; + + void disconnectIfConnected(); + // Interface required by Garbage Collectoin: - DEFINE_INLINE_TRACE() { } + DECLARE_VIRTUAL_TRACE(); // IDL exposed interface: bool connected() { return m_webGATT->connected; }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl index 9c878fdb..35e437a 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl
@@ -8,6 +8,7 @@ [ GarbageCollected, + ActiveDOMObject, RuntimeEnabled=WebBluetooth, ] interface BluetoothGATTRemoteServer // Implement ServiceEventHandlers interface: http://crbug.com/421670
diff --git a/third_party/WebKit/Source/modules/mediasession/HTMLMediaElementMediaSession.h b/third_party/WebKit/Source/modules/mediasession/HTMLMediaElementMediaSession.h index f847be8..b4cd9e4 100644 --- a/third_party/WebKit/Source/modules/mediasession/HTMLMediaElementMediaSession.h +++ b/third_party/WebKit/Source/modules/mediasession/HTMLMediaElementMediaSession.h
@@ -15,7 +15,7 @@ // A supplement to HTMLMediaElement responsible for the integration of // MediaSession with HTMLMediaElement. -class HTMLMediaElementMediaSession final : public NoBaseWillBeGarbageCollected<HTMLMediaElementMediaSession>, public WillBeHeapSupplement<HTMLMediaElement> { +class MODULES_EXPORT HTMLMediaElementMediaSession final : public NoBaseWillBeGarbageCollected<HTMLMediaElementMediaSession>, public WillBeHeapSupplement<HTMLMediaElement> { WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(HTMLMediaElementMediaSession); USING_FAST_MALLOC_WILL_BE_REMOVED(HTMLMediaElementMediaSession); public:
diff --git a/third_party/WebKit/Source/modules/mediasession/MediaSession.h b/third_party/WebKit/Source/modules/mediasession/MediaSession.h index 267f059..1ec2837 100644 --- a/third_party/WebKit/Source/modules/mediasession/MediaSession.h +++ b/third_party/WebKit/Source/modules/mediasession/MediaSession.h
@@ -24,6 +24,8 @@ public: static MediaSession* create(ExecutionContext*, ExceptionState&); + WebMediaSession* webMediaSession() { return m_webMediaSession.get(); } + ScriptPromise activate(ScriptState*); ScriptPromise deactivate(ScriptState*);
diff --git a/third_party/WebKit/Source/modules/notifications/Notification.idl b/third_party/WebKit/Source/modules/notifications/Notification.idl index b985e3db..24310c14 100644 --- a/third_party/WebKit/Source/modules/notifications/Notification.idl +++ b/third_party/WebKit/Source/modules/notifications/Notification.idl
@@ -65,7 +65,7 @@ readonly attribute DOMString lang; readonly attribute DOMString body; readonly attribute DOMString tag; - readonly attribute DOMString icon; + readonly attribute USVString icon; [RuntimeEnabled=NotificationExperimental] readonly attribute sequence<unsigned long>? vibrate; readonly attribute boolean silent;
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl b/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl index feba5b0e..67c36db 100644 --- a/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl +++ b/third_party/WebKit/Source/modules/notifications/NotificationOptions.idl
@@ -15,7 +15,7 @@ DOMString lang = ""; DOMString body = ""; DOMString tag = ""; - DOMString icon; + USVString icon; // TODO(sh919.park): vibrate should be ([Clamp] unsigned long or sequence<unsigned long>) (unsigned long or sequence<unsigned long>) vibrate; boolean silent = false;
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index 167b3807..00a0aef 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -58,6 +58,7 @@ #include "modules/device_orientation/DeviceOrientationController.h" #include "modules/encryptedmedia/HTMLMediaElementEncryptedMedia.h" #include "modules/gamepad/NavigatorGamepad.h" +#include "modules/mediasession/HTMLMediaElementMediaSession.h" #include "modules/mediasession/MediaSession.h" #include "modules/serviceworkers/NavigatorServiceWorker.h" #include "modules/storage/DOMWindowStorageController.h" @@ -818,11 +819,15 @@ if (!webFrame || !webFrame->client()) return nullptr; + WebMediaSession* webMediaSession = nullptr; + if (MediaSession* mediaSession = HTMLMediaElementMediaSession::session(htmlMediaElement)) + webMediaSession = mediaSession->webMediaSession(); + HTMLMediaElementEncryptedMedia& encryptedMedia = HTMLMediaElementEncryptedMedia::from(htmlMediaElement); WebString sinkId(HTMLMediaElementAudioOutputDevice::sinkId(htmlMediaElement)); return adoptPtr(webFrame->client()->createMediaPlayer(webFrame, loadType, url, client, &encryptedMedia, - encryptedMedia.contentDecryptionModule(), sinkId)); + encryptedMedia.contentDecryptionModule(), sinkId, webMediaSession)); } PassOwnPtr<WebMediaSession> FrameLoaderClientImpl::createWebMediaSession()
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp index beca4dd..3abba53 100644 --- a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp +++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -211,7 +211,7 @@ frameElement->contentDocument()->documentElement()->setAttribute(styleAttr, "background: green"); EXPECT_FALSE(compositor().needsAnimate()); - // Moving the frame back on screen to unthrottle it. + // Move the frame back on screen to unthrottle it. frameElement->setAttribute(styleAttr, ""); EXPECT_TRUE(compositor().needsAnimate()); @@ -251,6 +251,65 @@ EXPECT_EQ(50, divElement->clientWidth()); } +TEST_F(FrameThrottlingTest, UnthrottlingTriggersRepaint) +{ + // Create a hidden frame which is throttled. + SimRequest mainResource("https://example.com/", "text/html"); + SimRequest frameResource("https://example.com/iframe.html", "text/html"); + + loadURL("https://example.com/"); + mainResource.complete("<iframe id=frame sandbox src=iframe.html></iframe>"); + frameResource.complete("<style> html { background: green; } </style>"); + + // Move the frame offscreen to throttle it. + auto* frameElement = toHTMLIFrameElement(document().getElementById("frame")); + frameElement->setAttribute(styleAttr, "transform: translateY(480px)"); + EXPECT_FALSE(frameElement->contentDocument()->view()->shouldThrottleRendering()); + compositeFrame(); + EXPECT_TRUE(frameElement->contentDocument()->view()->shouldThrottleRendering()); + + // Scroll down to unthrottle the frame. The first frame we composite after + // scrolling won't contain the frame yet, but will schedule another repaint. + webView().mainFrameImpl()->frameView()->setScrollPosition(DoublePoint(0, 480), ProgrammaticScroll); + auto displayItems = compositeFrame(); + EXPECT_FALSE(displayItems.contains(SimCanvas::Rect, "green")); + + // Now the frame contents should be visible again. + auto displayItems2 = compositeFrame(); + EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green")); +} + +TEST_F(FrameThrottlingTest, ChangeStyleInThrottledFrame) +{ + // Create a hidden frame which is throttled. + SimRequest mainResource("https://example.com/", "text/html"); + SimRequest frameResource("https://example.com/iframe.html", "text/html"); + + loadURL("https://example.com/"); + mainResource.complete("<iframe id=frame sandbox src=iframe.html></iframe>"); + frameResource.complete("<style> html { background: red; } </style>"); + + // Move the frame offscreen to throttle it. + auto* frameElement = toHTMLIFrameElement(document().getElementById("frame")); + frameElement->setAttribute(styleAttr, "transform: translateY(480px)"); + EXPECT_FALSE(frameElement->contentDocument()->view()->shouldThrottleRendering()); + compositeFrame(); + EXPECT_TRUE(frameElement->contentDocument()->view()->shouldThrottleRendering()); + + // Change the background color of the frame's contents from red to green. + frameElement->contentDocument()->body()->setAttribute(styleAttr, "background: green"); + + // Scroll down to unthrottle the frame. + webView().mainFrameImpl()->frameView()->setScrollPosition(DoublePoint(0, 480), ProgrammaticScroll); + auto displayItems = compositeFrame(); + EXPECT_FALSE(displayItems.contains(SimCanvas::Rect, "red")); + EXPECT_FALSE(displayItems.contains(SimCanvas::Rect, "green")); + + // Make sure the new style shows up instead of the old one. + auto displayItems2 = compositeFrame(); + EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green")); +} + TEST(RemoteFrameThrottlingTest, ThrottledLocalRoot) { FrameTestHelpers::TestWebViewClient viewClient;
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index a57f5d7..86c77e29 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -113,7 +113,7 @@ // May return null. // WebContentDecryptionModule* may be null if one has not yet been set. - virtual WebMediaPlayer* createMediaPlayer(WebLocalFrame*, WebMediaPlayer::LoadType, const WebURL&, WebMediaPlayerClient*, WebMediaPlayerEncryptedMediaClient*, WebContentDecryptionModule*, const WebString& sinkId) { return 0; } + virtual WebMediaPlayer* createMediaPlayer(WebLocalFrame*, WebMediaPlayer::LoadType, const WebURL&, WebMediaPlayerClient*, WebMediaPlayerEncryptedMediaClient*, WebContentDecryptionModule*, const WebString& sinkId, WebMediaSession*) { return 0; } // May return null. virtual WebMediaSession* createMediaSession() { return 0; }
diff --git a/tools/android/loading/analyze.py b/tools/android/loading/analyze.py index 27294d38..5f15fe23 100755 --- a/tools/android/loading/analyze.py +++ b/tools/android/loading/analyze.py
@@ -24,6 +24,7 @@ import devil_chromium from pylib import constants +import content_classification_lens import device_setup import loading_model import loading_trace @@ -147,10 +148,14 @@ # TODO(mattcary): it would be nice to refactor so the --noads flag gets dealt # with here. -def _ProcessRequests(filename): +def _ProcessRequests(filename, ad_rules_filename='', + tracking_rules_filename=''): with open(filename) as f: - return loading_model.ResourceGraph( - loading_trace.LoadingTrace.FromJsonDict(json.load(f))) + trace = loading_trace.LoadingTrace.FromJsonDict(json.load(f)) + content_lens = ( + content_classification_lens.ContentClassificationLens.WithRulesFiles( + trace, ad_rules_filename, tracking_rules_filename)) + return loading_model.ResourceGraph(trace, content_lens) def InvalidCommand(cmd): @@ -185,8 +190,11 @@ parser.add_argument('--eog', action='store_true') parser.add_argument('--highlight') parser.add_argument('--noads', action='store_true') + parser.add_argument('--ad_rules', default='') + parser.add_argument('--tracking_rules', default='') args = parser.parse_args(arg_str) - graph = _ProcessRequests(args.request_json) + graph = _ProcessRequests( + args.request_json, args.ad_rules, args.tracking_rules) if args.noads: graph.Set(node_filter=graph.FilterAds) tmp = tempfile.NamedTemporaryFile()
diff --git a/tools/android/loading/content_classification_lens.py b/tools/android/loading/content_classification_lens.py new file mode 100644 index 0000000..2e8f0bd --- /dev/null +++ b/tools/android/loading/content_classification_lens.py
@@ -0,0 +1,118 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Labels requests according to the type of content they represent.""" + +import adblockparser # Available on PyPI, through pip. +import collections +import os + +import loading_trace +import request_track + + +class ContentClassificationLens(object): + """Associates requests and frames with the type of content they represent.""" + def __init__(self, trace, ad_rules, tracking_rules): + """Initializes an instance of ContentClassificationLens. + + Args: + trace: (LoadingTrace) loading trace. + ad_rules: ([str]) List of Adblock+ compatible rules used to classify ads. + tracking_rules: ([str]) List of Adblock+ compatible rules used to + classify tracking and analytics. + """ + self._trace = trace + self._requests = trace.request_track.GetEvents() + self._main_frame_id = trace.page_track.GetEvents()[0]['frame_id'] + self._frame_to_requests = collections.defaultdict(list) + self._ad_requests = set() + self._tracking_requests = set() + self._ad_matcher = _RulesMatcher(ad_rules, True) + self._tracking_matcher = _RulesMatcher(tracking_rules, True) + self._GroupRequestsByFrameId() + self._LabelRequests() + + def IsAdRequest(self, request): + """Returns True iff the request matches one of the ad_rules.""" + return request.request_id in self._ad_requests + + def IsTrackingRequest(self, request): + """Returns True iff the request matches one of the tracking_rules.""" + return request.request_id in self._tracking_requests + + def IsAdFrame(self, frame_id, ratio): + """A Frame is an Ad frame if more than |ratio| of its requests are + ad-related, and is not the main frame.""" + if frame_id == self._main_frame_id: + return False + ad_requests_count = sum(r in self._ad_requests + for r in self._frame_to_requests[frame_id]) + frame_requests_count = len(self._frame_to_requests[frame_id]) + return (float(ad_requests_count) / frame_requests_count) > ratio + + @classmethod + def WithRulesFiles(cls, trace, ad_rules_filename, tracking_rules_filename): + """Returns an instance of ContentClassificationLens with the rules read + from files. + """ + ad_rules = [] + tracking_rules = [] + if os.path.exists(ad_rules_filename): + ad_rules = open(ad_rules_filename, 'r').readlines() + if os.path.exists(tracking_rules_filename): + tracking_rules = open(tracking_rules_filename, 'r').readlines() + return ContentClassificationLens(trace, ad_rules, tracking_rules) + + def _GroupRequestsByFrameId(self): + for request in self._requests: + frame_id = request.frame_id + self._frame_to_requests[frame_id].append(request.request_id) + + def _LabelRequests(self): + for request in self._requests: + request_id = request.request_id + if self._ad_matcher.Matches(request): + self._ad_requests.add(request_id) + if self._tracking_matcher.Matches(request): + self._tracking_requests.add(request_id) + + +class _RulesMatcher(object): + """Matches requests with rules in Adblock+ format.""" + _WHITELIST_PREFIX = '@@' + _RESOURCE_TYPE_TO_OPTIONS_KEY = { + 'Script': 'script', 'Stylesheet': 'stylesheet', 'Image': 'image', + 'XHR': 'xmlhttprequest'} + def __init__(self, rules, no_whitelist): + """Initializes an instance of _RulesMatcher. + + Args: + rules: ([str]) list of rules. + no_whitelist: (bool) Whether the whitelisting rules should be ignored. + """ + self._rules = self._FilterRules(rules, no_whitelist) + self._matcher = adblockparser.AdblockRules(self._rules) + + def Matches(self, request): + """Returns whether a request matches one of the rules.""" + url = request.url + return self._matcher.should_block(url, self._GetOptions(request)) + + @classmethod + def _GetOptions(cls, request): + options = {} + resource_type = request.resource_type + option = cls._RESOURCE_TYPE_TO_OPTIONS_KEY.get(resource_type) + if option: + options[option] = True + return options + + @classmethod + def _FilterRules(cls, rules, no_whitelist): + if not no_whitelist: + return rules + else: + return [rule for rule in rules + if not rule.startswith(cls._WHITELIST_PREFIX)]
diff --git a/tools/android/loading/content_classification_lens_unittest.py b/tools/android/loading/content_classification_lens_unittest.py new file mode 100644 index 0000000..cca7d52b --- /dev/null +++ b/tools/android/loading/content_classification_lens_unittest.py
@@ -0,0 +1,85 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import copy +import unittest + +from content_classification_lens import (ContentClassificationLens, + _RulesMatcher) +from request_track import (Request, TimingFromDict) +import test_utils + + +class ContentClassificationLensTestCase(unittest.TestCase): + _REQUEST = Request.FromJsonDict({'url': 'http://bla.com', + 'request_id': '1234.1', + 'frame_id': '123.1', + 'initiator': {'type': 'other'}, + 'timestamp': 2, + 'timing': TimingFromDict({})}) + _MAIN_FRAME_ID = '123.1' + _PAGE_EVENTS = [{'method': 'Page.frameStartedLoading', + 'frame_id': _MAIN_FRAME_ID}, + {'method': 'Page.frameAttached', + 'frame_id': '123.13', 'parent_frame_id': _MAIN_FRAME_ID}] + _RULES = ['bla.com'] + + def testAdRequest(self): + trace = test_utils.LoadingTraceFromEvents( + [self._REQUEST], self._PAGE_EVENTS) + lens = ContentClassificationLens(trace, self._RULES, []) + self.assertTrue(lens.IsAdRequest(self._REQUEST)) + self.assertFalse(lens.IsTrackingRequest(self._REQUEST)) + + def testTrackingRequest(self): + trace = test_utils.LoadingTraceFromEvents( + [self._REQUEST], self._PAGE_EVENTS) + lens = ContentClassificationLens(trace, [], self._RULES) + self.assertFalse(lens.IsAdRequest(self._REQUEST)) + self.assertTrue(lens.IsTrackingRequest(self._REQUEST)) + + def testMainFrameIsNotAdFrame(self): + trace = test_utils.LoadingTraceFromEvents( + [self._REQUEST] * 10, self._PAGE_EVENTS) + lens = ContentClassificationLens(trace, self._RULES, []) + self.assertFalse(lens.IsAdFrame(self._MAIN_FRAME_ID, .5)) + + def testAdFrame(self): + request = self._REQUEST + request.frame_id = '123.123' + trace = test_utils.LoadingTraceFromEvents( + [request] * 10 + [self._REQUEST] * 5, self._PAGE_EVENTS) + lens = ContentClassificationLens(trace, self._RULES, []) + self.assertTrue(lens.IsAdFrame(request.frame_id, .5)) + + +class _MatcherTestCase(unittest.TestCase): + _RULES_WITH_WHITELIST = ['/thisisanad.', '@@myadvertisingdomain.com/*', + '@@||www.mydomain.com/ads/$elemhide'] + _SCRIPT_RULE = 'domainwithscripts.com/*$script' + _SCRIPT_REQUEST = Request.FromJsonDict( + {'url': 'http://domainwithscripts.com/bla.js', + 'resource_type': 'Script', + 'request_id': '1234.1', + 'frame_id': '123.1', + 'initiator': {'type': 'other'}, + 'timestamp': 2, + 'timing': TimingFromDict({})}) + + def testRemovesWhitelistRules(self): + matcher = _RulesMatcher(self._RULES_WITH_WHITELIST, False) + self.assertEquals(3, len(matcher._rules)) + matcher = _RulesMatcher(self._RULES_WITH_WHITELIST, True) + self.assertEquals(1, len(matcher._rules)) + + def testScriptRule(self): + matcher = _RulesMatcher([self._SCRIPT_RULE], False) + request = copy.deepcopy(self._SCRIPT_REQUEST) + request.resource_type = 'Stylesheet' + self.assertFalse(matcher.Matches(request)) + self.assertTrue(matcher.Matches(self._SCRIPT_REQUEST)) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/android/loading/loading_model.py b/tools/android/loading/loading_model.py index 155da1dd..b6aeca6 100644 --- a/tools/android/loading/loading_model.py +++ b/tools/android/loading/loading_model.py
@@ -30,14 +30,17 @@ Set parameters: cache_all: if true, assume zero loading time for all resources. """ - def __init__(self, trace): + def __init__(self, trace, content_lens=None): """Create from a LoadingTrace (or json of a trace). Args: trace: (LoadingTrace/JSON) Loading trace or JSON of a trace. + content_lens: (ContentClassificationLens) Lens used to annotate the + nodes, or None. """ if type(trace) == dict: trace = loading_trace.LoadingTrace.FromJsonDict(trace) + self._content_lens = content_lens self._BuildDag(trace) self._global_start = min([n.StartTime() for n in self._node_info]) # Sort before splitting children so that we can correctly dectect if a @@ -244,7 +247,9 @@ for s in n.Successors(): style = 'color = orange' annotations = self._EdgeAnnotation(n, s) - if 'parser' in annotations: + if 'redirect' in annotations: + style = 'color = black' + elif 'parser' in annotations: style = 'color = red' elif 'stack' in annotations: style = 'color = blue' @@ -339,6 +344,8 @@ request: The request associated with this node. """ self._request = request + self._is_ad = False + self._is_tracking = False self._node = node self._edge_costs = {} self._edge_annotations = {} @@ -357,6 +364,21 @@ def Index(self): return self._node.Index() + def SetRequestContent(self, is_ad, is_tracking): + """Sets the kind of content the request relates to. + + Args: + is_ad: (bool) Whether the request is an Ad. + is_tracking: (bool) Whether the request is related to tracking. + """ + (self._is_ad, self._is_tracking) = (is_ad, is_tracking) + + def IsAd(self): + return self._is_ad + + def IsTracking(self): + return self._is_tracking + def Request(self): return self._request @@ -481,6 +503,9 @@ index_by_request[request] = next_index node = dag.Node(next_index) node_info = self._NodeInfo(node, request) + if self._content_lens: + node.SetRequestContent(self._content_lens.IsAdRequest(request), + self._content_lens.IsTrackingRequest(request)) self._nodes.append(node) self._node_info.append(node_info) @@ -606,6 +631,8 @@ if fragment in node_info.Url(): styles.append('dotted') break + if node_info.IsAd() or node_info.IsTracking(): + styles += ['bold', 'diagonals'] return ('%d [label = "%s\\n%.2f->%.2f (%.2f)"; style = "%s"; ' 'fillcolor = %s; shape = %s];\n' % (index, node_info.ShortName(),
diff --git a/tools/android/loading/loading_model_unittest.py b/tools/android/loading/loading_model_unittest.py index 7033cef..b866136 100644 --- a/tools/android/loading/loading_model_unittest.py +++ b/tools/android/loading/loading_model_unittest.py
@@ -72,7 +72,9 @@ self.MakeParserRequest(1, 0, 102, 103).ToJsonDict(), self.MakeParserRequest(2, 0, 102, 103).ToJsonDict(), self.MakeParserRequest(3, 2, 104, 105).ToJsonDict()], - 'metadata': { 'duplicates_count' : 0 }}, + 'metadata': { + request_track.RequestTrack._DUPLICATES_KEY: 0, + request_track.RequestTrack._INCONSISTENT_INITIATORS_KEY: 0}}, 'url': 'foo.com', 'tracing_track': {'events': []}, 'page_track': {'events': []},
diff --git a/tools/android/loading/request_dependencies_lens.py b/tools/android/loading/request_dependencies_lens.py index 47ea3af5..81289572 100644 --- a/tools/android/loading/request_dependencies_lens.py +++ b/tools/android/loading/request_dependencies_lens.py
@@ -64,8 +64,7 @@ """ reason = request.initiator['type'] assert reason in request_track.Request.INITIATORS - # Redirect suffixes are added in RequestTrack. - if request.request_id.endswith(request_track.RequestTrack.REDIRECT_SUFFIX): + if reason == 'redirect': return self._GetInitiatingRequestRedirect(request) elif reason == 'parser': return self._GetInitiatingRequestParser(request) @@ -76,14 +75,11 @@ return self._GetInitiatingRequestOther(request) def _GetInitiatingRequestRedirect(self, request): - request_id = request.request_id[:request.request_id.index( - request_track.RequestTrack.REDIRECT_SUFFIX)] - assert request_id in self._requests_by_id - dependent_request = self._requests_by_id[request_id] - assert request.timing.request_time < \ - dependent_request.timing.request_time, '.\n'.join( - [str(request), str(dependent_request)]) - return (request, dependent_request, 'redirect') + assert request_track.Request.INITIATING_REQUEST in request.initiator + initiating_request_id = request.initiator[ + request_track.Request.INITIATING_REQUEST] + assert initiating_request_id in self._requests_by_id + return (self._requests_by_id[initiating_request_id], request, 'redirect') def _GetInitiatingRequestParser(self, request): url = request.initiator['url']
diff --git a/tools/android/loading/request_dependencies_lens_unittest.py b/tools/android/loading/request_dependencies_lens_unittest.py index 4fc5d907..0ab7403b 100644 --- a/tools/android/loading/request_dependencies_lens_unittest.py +++ b/tools/android/loading/request_dependencies_lens_unittest.py
@@ -13,9 +13,17 @@ class RequestDependencyLensTestCase(unittest.TestCase): _REDIRECT_REQUEST = Request.FromJsonDict( - {'url': 'http://bla.com', 'request_id': '1234.1.redirect', + {'url': 'http://bla.com', 'request_id': '1234.redirect.1', 'initiator': {'type': 'other'}, 'timestamp': 1, 'timing': TimingFromDict({})}) + _REDIRECTED_REQUEST = Request.FromJsonDict({ + 'url': 'http://bla.com', + 'request_id': '1234.1', + 'frame_id': '123.1', + 'initiator': {'type': 'redirect', + 'initiating_request': '1234.redirect.1'}, + 'timestamp': 2, + 'timing': TimingFromDict({})}) _REQUEST = Request.FromJsonDict({'url': 'http://bla.com', 'request_id': '1234.1', 'frame_id': '123.1', @@ -55,7 +63,7 @@ def testRedirectDependency(self): loading_trace = test_utils.LoadingTraceFromEvents( - [self._REDIRECT_REQUEST, self._REQUEST]) + [self._REDIRECT_REQUEST, self._REDIRECTED_REQUEST]) request_dependencies_lens = RequestDependencyLens(loading_trace) deps = request_dependencies_lens.GetRequestDependencies() self.assertEquals(1, len(deps)) @@ -86,7 +94,7 @@ def testSeveralDependencies(self): loading_trace = test_utils.LoadingTraceFromEvents( - [self._REDIRECT_REQUEST, self._REQUEST, self._JS_REQUEST, + [self._REDIRECT_REQUEST, self._REDIRECTED_REQUEST, self._JS_REQUEST, self._JS_REQUEST_2]) request_dependencies_lens = RequestDependencyLens(loading_trace) deps = request_dependencies_lens.GetRequestDependencies()
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py index 60a54e5..566fb3c3 100644 --- a/tools/android/loading/request_track.py +++ b/tools/android/loading/request_track.py
@@ -46,7 +46,7 @@ third_party/WebKit/Source/devtools/protocol.json. Fields: - request_id: (str) unique request ID. Postfixed with REDIRECT_SUFFIX for + request_id: (str) unique request ID. Postfixed with _REDIRECT_SUFFIX for redirects. frame_id: (str) unique frame identifier. loader_id: (str) unique frame identifier. @@ -77,7 +77,9 @@ RESOURCE_TYPES = ('Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Script', 'TextTrack', 'XHR', 'Fetch', 'EventSource', 'WebSocket', 'Manifest', 'Other') - INITIATORS = ('parser', 'script', 'other') + INITIATORS = ('parser', 'script', 'other', 'redirect') + INITIATING_REQUEST = 'initiating_request' + ORIGINAL_INITIATOR = 'original_initiator' def __init__(self): self.request_id = None self.frame_id = None @@ -172,7 +174,7 @@ class RequestTrack(devtools_monitor.Track): """Aggregates request data.""" - REDIRECT_SUFFIX = '.redirect' + _REDIRECT_SUFFIX = '.redirect' # Request status _STATUS_SENT = 0 _STATUS_RESPONSE = 1 @@ -183,12 +185,14 @@ _EVENTS_KEY = 'events' _METADATA_KEY = 'metadata' _DUPLICATES_KEY = 'duplicates_count' + _INCONSISTENT_INITIATORS_KEY = 'inconsistent_initiators' def __init__(self, connection): super(RequestTrack, self).__init__(connection) self._connection = connection self._requests = [] self._requests_in_flight = {} # requestId -> (request, status) self._completed_requests_by_id = {} + self._redirects_count_by_id = collections.defaultdict(int) if connection: # Optional for testing. for method in RequestTrack._METHOD_TO_HANDLER: self._connection.RegisterListener(method, self) @@ -196,6 +200,7 @@ # detect this. self._request_id_to_response_received = {} self.duplicates_count = 0 + self.inconsistent_initiators_count = 0 def Handle(self, method, msg): assert method in RequestTrack._METHOD_TO_HANDLER @@ -214,7 +219,10 @@ logging.warning('Requests in flight, will be ignored in the dump') return {self._EVENTS_KEY: [ request.ToJsonDict() for request in self._requests], - self._METADATA_KEY: {self._DUPLICATES_KEY: self.duplicates_count}} + self._METADATA_KEY: { + self._DUPLICATES_KEY: self.duplicates_count, + self._INCONSISTENT_INITIATORS_KEY: + self.inconsistent_initiators_count}} @classmethod def FromJsonDict(cls, json_dict): @@ -224,14 +232,18 @@ requests = [Request.FromJsonDict(request) for request in json_dict[cls._EVENTS_KEY]] result._requests = requests - result.duplicates_count = json_dict[cls._METADATA_KEY][cls._DUPLICATES_KEY] + metadata = json_dict[cls._METADATA_KEY] + result.duplicates_count = metadata.get(cls._DUPLICATES_KEY, 0) + result.inconsistent_initiators_count = metadata.get( + cls._INCONSISTENT_INITIATORS_KEY, 0) return result def _RequestWillBeSent(self, request_id, params): # Several "requestWillBeSent" events can be dispatched in a row in the case # of redirects. + redirect_initiator = None if request_id in self._requests_in_flight: - self._HandleRedirect(request_id, params) + redirect_initiator = self._HandleRedirect(request_id, params) assert (request_id not in self._requests_in_flight and request_id not in self._completed_requests_by_id) r = Request() @@ -247,6 +259,16 @@ ('headers', 'headers'), ('initialPriority', 'initial_priority'))) r.resource_type = params.get('type', 'Other') + if redirect_initiator: + original_initiator = r.initiator + r.initiator = redirect_initiator + r.initiator[Request.ORIGINAL_INITIATOR] = original_initiator + initiating_request = self._completed_requests_by_id[ + redirect_initiator[Request.INITIATING_REQUEST]] + initiating_initiator = initiating_request.initiator.get( + Request.ORIGINAL_INITIATOR, initiating_request.initiator) + if initiating_initiator != original_initiator: + self.inconsistent_initiators_count += 1 self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_SENT) def _HandleRedirect(self, request_id, params): @@ -256,15 +278,23 @@ # one. Finalize the first request. assert 'redirectResponse' in params redirect_response = params['redirectResponse'] + _CopyFromDictToObject(redirect_response, r, (('headers', 'response_headers'), ('encodedDataLength', 'encoded_data_length'), ('fromDiskCache', 'from_disk_cache'))) r.timing = TimingFromDict(redirect_response['timing']) - r.request_id = request_id + self.REDIRECT_SUFFIX + + redirect_index = self._redirects_count_by_id[request_id] + self._redirects_count_by_id[request_id] += 1 + r.request_id = '%s%s.%d' % (request_id, self._REDIRECT_SUFFIX, + redirect_index + 1) + initiator = { + 'type': 'redirect', Request.INITIATING_REQUEST: r.request_id} self._requests_in_flight[r.request_id] = (r, RequestTrack._STATUS_FINISHED) del self._requests_in_flight[request_id] self._FinalizeRequest(r.request_id) + return initiator def _RequestServedFromCache(self, request_id, _): assert request_id in self._requests_in_flight
diff --git a/tools/android/loading/request_track_unittest.py b/tools/android/loading/request_track_unittest.py index fde7399..e742f60 100644 --- a/tools/android/loading/request_track_unittest.py +++ b/tools/android/loading/request_track_unittest.py
@@ -195,7 +195,47 @@ self.assertEquals(1, len(self.request_track.GetEvents())) redirect_request = self.request_track.GetEvents()[0] self.assertTrue(redirect_request.request_id.endswith( - RequestTrack.REDIRECT_SUFFIX)) + RequestTrack._REDIRECT_SUFFIX + '.1')) + request = self.request_track._requests_in_flight.values()[0][0] + self.assertEquals('redirect', request.initiator['type']) + self.assertEquals( + redirect_request.request_id, + request.initiator[Request.INITIATING_REQUEST]) + self.assertEquals(0, self.request_track.inconsistent_initiators_count) + + def testMultipleRedirects(self): + self.request_track.Handle('Network.requestWillBeSent', + RequestTrackTestCase._REQUEST_WILL_BE_SENT) + self.request_track.Handle('Network.requestWillBeSent', + RequestTrackTestCase._REDIRECT) + self.request_track.Handle('Network.requestWillBeSent', + RequestTrackTestCase._REDIRECT) + self.assertEquals(1, len(self.request_track._requests_in_flight)) + self.assertEquals(2, len(self.request_track.GetEvents())) + first_redirect_request = self.request_track.GetEvents()[0] + self.assertTrue(first_redirect_request.request_id.endswith( + RequestTrack._REDIRECT_SUFFIX + '.1')) + second_redirect_request = self.request_track.GetEvents()[1] + self.assertTrue(second_redirect_request.request_id.endswith( + RequestTrack._REDIRECT_SUFFIX + '.2')) + self.assertEquals('redirect', second_redirect_request.initiator['type']) + self.assertEquals( + first_redirect_request.request_id, + second_redirect_request.initiator[Request.INITIATING_REQUEST]) + request = self.request_track._requests_in_flight.values()[0][0] + self.assertEquals('redirect', request.initiator['type']) + self.assertEquals( + second_redirect_request.request_id, + request.initiator[Request.INITIATING_REQUEST]) + self.assertEquals(0, self.request_track.inconsistent_initiators_count) + + def testInconsistentInitiators(self): + self.request_track.Handle('Network.requestWillBeSent', + RequestTrackTestCase._REQUEST_WILL_BE_SENT) + request = copy.deepcopy(RequestTrackTestCase._REDIRECT) + request['params']['initiator']['type'] = 'script' + self.request_track.Handle('Network.requestWillBeSent', request) + self.assertEquals(1, self.request_track.inconsistent_initiators_count) def testRejectDuplicates(self): msg = RequestTrackTestCase._REQUEST_WILL_BE_SENT @@ -281,6 +321,7 @@ def testCanDeserialize(self): self._ValidSequence(self.request_track) self.request_track.duplicates_count = 142 + self.request_track.inconsistent_initiators_count = 123 json_dict = self.request_track.ToJsonDict() request_track = RequestTrack.FromJsonDict(json_dict) self.assertEquals(self.request_track, request_track)
diff --git a/tools/battor_agent/BUILD.gn b/tools/battor_agent/BUILD.gn index 2f6dd284..1a057f3 100644 --- a/tools/battor_agent/BUILD.gn +++ b/tools/battor_agent/BUILD.gn
@@ -28,6 +28,8 @@ "battor_connection_impl.cc", "battor_connection_impl.h", "battor_error.h", + "battor_finder.cc", + "battor_finder.h", "battor_sample_converter.cc", "battor_sample_converter.h", ]
diff --git a/tools/battor_agent/DEPS b/tools/battor_agent/DEPS index 67358f38..b40de52 100644 --- a/tools/battor_agent/DEPS +++ b/tools/battor_agent/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+device/serial", + "+mojo/public", "+net/base", ] \ No newline at end of file
diff --git a/tools/battor_agent/battor_agent.gyp b/tools/battor_agent/battor_agent.gyp index 051f66dc..c34c5cd 100644 --- a/tools/battor_agent/battor_agent.gyp +++ b/tools/battor_agent/battor_agent.gyp
@@ -35,6 +35,8 @@ 'battor_connection_impl.cc', 'battor_connection_impl.h', 'battor_error.h', + 'battor_finder.cc', + 'battor_finder.h', 'battor_sample_converter.cc', 'battor_sample_converter.h', ],
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc index 360146d..93036e2fcb 100644 --- a/tools/battor_agent/battor_agent_bin.cc +++ b/tools/battor_agent/battor_agent_bin.cc
@@ -19,6 +19,7 @@ #include "base/threading/thread.h" #include "tools/battor_agent/battor_agent.h" #include "tools/battor_agent/battor_error.h" +#include "tools/battor_agent/battor_finder.h" using std::cout; using std::endl; @@ -47,12 +48,11 @@ cout << battor::BattOrAgent::SupportsExplicitClockSync() << endl; } -// Retrieves argument argnum from the argument list, printing the usage -// guidelines and exiting with an error code if the argument doesn't exist. +// Retrieves argument argnum from the argument list, or an empty string if the +// argument doesn't exist. std::string GetArg(int argnum, int argc, char* argv[]) { if (argnum >= argc) { - PrintUsage(); - exit(1); + return std::string(); } return argv[argnum]; @@ -89,6 +89,10 @@ // Runs the BattOr binary and returns the exit code. int Run(int argc, char* argv[]) { std::string cmd = GetArg(1, argc, argv); + if (cmd.empty()) { + PrintUsage(); + exit(1); + } // SupportsExplicitClockSync doesn't need to use the serial connection, so // handle it separately. @@ -98,6 +102,18 @@ } std::string path = GetArg(2, argc, argv); + // If no path is specified, see if we can find a BattOr and use that. + if (path.empty()) + path = BattOrFinder::FindBattOr(); + + // If we don't have any BattOr to use, exit. + if (path.empty()) { + cout << "Unable to find a BattOr, and no explicit BattOr path was " + "specified." + << endl; + exit(1); + } + SetUp(path); if (cmd == "StartTracing") {
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc index ad86f487..d1b43e9 100644 --- a/tools/battor_agent/battor_agent_unittest.cc +++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -472,9 +472,8 @@ // Send an empty last frame to indicate that we're done. BattOrFrameHeader frame_header3{0, 0 * sizeof(RawBattOrSample)}; - RawBattOrSample frame3[] = {}; GetAgent()->OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, - CreateFrame(frame_header3, frame3, 0)); + CreateFrame(frame_header3, nullptr, 0)); EXPECT_TRUE(IsCommandComplete()); EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError()); @@ -523,9 +522,8 @@ GetTaskRunner()->RunUntilIdle(); BattOrFrameHeader frame_header{0, 0}; - RawBattOrSample frame[] = {}; GetAgent()->OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, - CreateFrame(frame_header, frame, 0)); + CreateFrame(frame_header, nullptr, 0)); GetTaskRunner()->RunUntilIdle(); EXPECT_TRUE(IsCommandComplete()); @@ -577,9 +575,8 @@ GetTaskRunner()->RunUntilIdle(); BattOrFrameHeader frame_header{0, 0}; - RawBattOrSample frame[] = {}; GetAgent()->OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, - CreateFrame(frame_header, frame, 0)); + CreateFrame(frame_header, nullptr, 0)); GetTaskRunner()->RunUntilIdle(); EXPECT_TRUE(IsCommandComplete()); @@ -607,9 +604,8 @@ GetTaskRunner()->RunUntilIdle(); BattOrFrameHeader frame_header{0, 0}; - RawBattOrSample frame[] = {}; GetAgent()->OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, - CreateFrame(frame_header, frame, 0)); + CreateFrame(frame_header, nullptr, 0)); GetTaskRunner()->RunUntilIdle(); EXPECT_TRUE(IsCommandComplete()); @@ -651,9 +647,8 @@ } BattOrFrameHeader frame_header2{0, 0}; - RawBattOrSample frame2[] = {}; GetAgent()->OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, - CreateFrame(frame_header2, frame2, 0)); + CreateFrame(frame_header2, nullptr, 0)); GetTaskRunner()->RunUntilIdle(); EXPECT_TRUE(IsCommandComplete());
diff --git a/tools/battor_agent/battor_finder.cc b/tools/battor_agent/battor_finder.cc new file mode 100644 index 0000000..b0e32db --- /dev/null +++ b/tools/battor_agent/battor_finder.cc
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/battor_agent/battor_finder.h" + +#include "device/serial/serial.mojom.h" +#include "device/serial/serial_device_enumerator.h" +#include "mojo/public/cpp/bindings/array.h" + +namespace battor { + +namespace { + +// The USB display name prefix that all BattOrs have. +const char kBattOrDisplayNamePrefix[] = "BattOr"; + +} // namespace + +// Returns the path of the first BattOr that we find. +std::string BattOrFinder::FindBattOr() { + scoped_ptr<device::SerialDeviceEnumerator> serial_device_enumerator = + device::SerialDeviceEnumerator::Create(); + + mojo::Array<device::serial::DeviceInfoPtr> devices = + serial_device_enumerator->GetDevices(); + + for (size_t i = 0; i < devices.size(); i++) { + std::string display_name = devices[i]->display_name.get(); + + if (display_name.find(kBattOrDisplayNamePrefix) != std::string::npos) { + return devices[i]->path; + } + } + + return std::string(); +} + +} // namespace battor
diff --git a/tools/battor_agent/battor_finder.h b/tools/battor_agent/battor_finder.h new file mode 100644 index 0000000..fe6fa79 --- /dev/null +++ b/tools/battor_agent/battor_finder.h
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_ +#define TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_ + +#include <string> + +#include "base/macros.h" + +namespace battor { + +class BattOrFinder { + public: + static std::string FindBattOr(); + + DISALLOW_COPY_AND_ASSIGN(BattOrFinder); +}; + +} // namespace battor + +#endif // TOOLS_BATTOR_AGENT_BATTOR_FINDER_H_
diff --git a/tools/battor_agent/battor_sample_converter_unittest.cc b/tools/battor_agent/battor_sample_converter_unittest.cc index a20f878..f0b9935 100644 --- a/tools/battor_agent/battor_sample_converter_unittest.cc +++ b/tools/battor_agent/battor_sample_converter_unittest.cc
@@ -15,12 +15,12 @@ TEST(BattOrSampleConverterTest, ToSampleSimple) { BattOrEEPROM eeprom; - eeprom.r1 = 1; - eeprom.r2 = 1; - eeprom.r3 = 1; - eeprom.low_gain = 1; - eeprom.low_gain_correction_offset = 0; - eeprom.low_gain_correction_factor = 1; + eeprom.r1 = 1.0f; + eeprom.r2 = 1.0f; + eeprom.r3 = 1.0f; + eeprom.low_gain = 1.0f; + eeprom.low_gain_correction_offset = 0.0f; + eeprom.low_gain_correction_factor = 1.0f; eeprom.sd_sample_rate = 1000; // Create a calibration frame with a baseline voltage and current of zero. @@ -39,12 +39,12 @@ TEST(BattOrSampleConverterTest, ToSampleNonZeroBaseline) { BattOrEEPROM eeprom; - eeprom.r1 = 1; - eeprom.r2 = 1; - eeprom.r3 = 1; - eeprom.low_gain = 1; - eeprom.low_gain_correction_offset = 0; - eeprom.low_gain_correction_factor = 1; + eeprom.r1 = 1.0f; + eeprom.r2 = 1.0f; + eeprom.r3 = 1.0f; + eeprom.low_gain = 1.0f; + eeprom.low_gain_correction_offset = 0.0f; + eeprom.low_gain_correction_factor = 1.0f; eeprom.sd_sample_rate = 1000; // Create a calibration frame with a baseline voltage and current of zero. @@ -63,12 +63,12 @@ TEST(BattOrSampleConverterTest, ToSampleNonZeroMultiSampleBaseline) { BattOrEEPROM eeprom; - eeprom.r1 = 1; - eeprom.r2 = 1; - eeprom.r3 = 1; - eeprom.low_gain = 1; - eeprom.low_gain_correction_offset = 0; - eeprom.low_gain_correction_factor = 1; + eeprom.r1 = 1.0f; + eeprom.r2 = 1.0f; + eeprom.r3 = 1.0f; + eeprom.low_gain = 1.0f; + eeprom.low_gain_correction_offset = 0.0f; + eeprom.low_gain_correction_factor = 1.0f; eeprom.sd_sample_rate = 1000; // Create a calibration frame with a baseline voltage and current of zero. @@ -88,12 +88,12 @@ TEST(BattOrSampleConverterTest, ToSampleRealValues) { BattOrEEPROM eeprom; - eeprom.r1 = 10; - eeprom.r2 = 14; - eeprom.r3 = 17; + eeprom.r1 = 10.0f; + eeprom.r2 = 14.0f; + eeprom.r3 = 17.0f; eeprom.low_gain = 1.5; - eeprom.low_gain_correction_offset = 0.03; - eeprom.low_gain_correction_factor = 4; + eeprom.low_gain_correction_offset = 0.03f; + eeprom.low_gain_correction_factor = 4.0f; eeprom.sd_sample_rate = 1000; // Create a calibration frame with a baseline voltage and current of zero. @@ -113,12 +113,12 @@ TEST(BattOrSampleConverterTest, ToSampleRealNegativeValues) { BattOrEEPROM eeprom; - eeprom.r1 = 10; - eeprom.r2 = 14; - eeprom.r3 = 17; + eeprom.r1 = 10.0f; + eeprom.r2 = 14.0f; + eeprom.r3 = 17.0f; eeprom.low_gain = 1.5; - eeprom.low_gain_correction_offset = 0.03; - eeprom.low_gain_correction_factor = 4; + eeprom.low_gain_correction_offset = 0.03f; + eeprom.low_gain_correction_factor = 4.0f; eeprom.sd_sample_rate = 1000; // Create a calibration frame with a baseline voltage and current of zero. @@ -137,12 +137,12 @@ TEST(BattOrSampleConverterTest, ToSampleMultipleSamples) { BattOrEEPROM eeprom; - eeprom.r1 = 1; - eeprom.r2 = 1; - eeprom.r3 = 1; - eeprom.low_gain = 1; - eeprom.low_gain_correction_offset = 0; - eeprom.low_gain_correction_factor = 1; + eeprom.r1 = 1.0f; + eeprom.r2 = 1.0f; + eeprom.r3 = 1.0f; + eeprom.low_gain = 1.0f; + eeprom.low_gain_correction_offset = 0.0f; + eeprom.low_gain_correction_factor = 1.0f; eeprom.sd_sample_rate = 50; std::vector<RawBattOrSample> calibration_frame;
diff --git a/tools/cr/cr/commands/run.py b/tools/cr/cr/commands/run.py index 1b97b75..15d7db06 100644 --- a/tools/cr/cr/commands/run.py +++ b/tools/cr/cr/commands/run.py
@@ -25,7 +25,7 @@ cr.Builder.AddArguments(self, parser) cr.Installer.AddArguments(self, parser) cr.Runner.AddArguments(self, parser) - cr.Target.AddArguments(self, parser, allow_multiple=True) + cr.Target.AddArguments(self, parser, allow_multiple=False) self.ConsumeArgs(parser, 'the binary') return parser
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md index 97f12f2..85fba66 100644 --- a/tools/gn/docs/reference.md +++ b/tools/gn/docs/reference.md
@@ -1327,7 +1327,8 @@ ## **forward_variables_from**: Copies variables from a different scope. ``` - forward_variables_from(from_scope, variable_list_or_star) + forward_variables_from(from_scope, variable_list_or_star, + variable_to_not_forward_list = []) Copies the given variables from the given scope to the local scope if they exist. This is normally used in the context of templates to @@ -1354,6 +1355,10 @@ is never applied by this function. It's assumed than any desired filtering was already done when sources was set on the from_scope. + If variables_to_not_forward_list is non-empty, then it must contains + a list of variable names that will not be forwarded. This is mostly + useful when variable_list_or_star has a value of "*". + ``` ### **Examples** @@ -1383,7 +1388,19 @@ target(my_wrapper_target_type, target_name) { forward_variables_from(invoker, "*") } - } + } + + # A template that wraps another. It adds behavior based on one + # variable, and forwards all others to the nested target. + template("my_ios_test_app") { + ios_test_app(target_name) { + forward_variables_from(invoker, "*", ["test_bundle_name"]) + if (!defined(extra_substitutions)) { + extra_substitutions = [] + } + extra_substitutions += [ "BUNDLE_ID_TEST_NAME=$test_bundle_name" ] + } + } ```
diff --git a/tools/gn/function_forward_variables_from.cc b/tools/gn/function_forward_variables_from.cc index 9c97a51c..ee14128 100644 --- a/tools/gn/function_forward_variables_from.cc +++ b/tools/gn/function_forward_variables_from.cc
@@ -14,6 +14,7 @@ void ForwardAllValues(const FunctionCallNode* function, Scope* source, Scope* dest, + const std::set<std::string>& exclusion_set, Err* err) { Scope::MergeOptions options; // This function needs to clobber existing for it to be useful. It will be @@ -23,6 +24,7 @@ options.clobber_existing = true; options.skip_private_vars = true; options.mark_dest_used = false; + options.excluded_values = exclusion_set; source->NonRecursiveMergeTo(dest, options, function, "source scope", err); source->MarkAllUsed(); @@ -31,10 +33,13 @@ void ForwardValuesFromList(Scope* source, Scope* dest, const std::vector<Value>& list, + const std::set<std::string>& exclusion_set, Err* err) { for (const Value& cur : list) { if (!cur.VerifyTypeIs(Value::STRING, err)) return; + if (exclusion_set.find(cur.string_value()) != exclusion_set.end()) + continue; const Value* value = source->GetValue(cur.string_value(), true); if (value) { // Use the storage key for the original value rather than the string in @@ -66,7 +71,8 @@ const char kForwardVariablesFrom_Help[] = "forward_variables_from: Copies variables from a different scope.\n" "\n" - " forward_variables_from(from_scope, variable_list_or_star)\n" + " forward_variables_from(from_scope, variable_list_or_star,\n" + " variable_to_not_forward_list = [])\n" "\n" " Copies the given variables from the given scope to the local scope\n" " if they exist. This is normally used in the context of templates to\n" @@ -94,6 +100,10 @@ " is never applied by this function. It's assumed than any desired\n" " filtering was already done when sources was set on the from_scope.\n" "\n" + " If variables_to_not_forward_list is non-empty, then it must contains\n" + " a list of variable names that will not be forwarded. This is mostly\n" + " useful when variable_list_or_star has a value of \"*\".\n" + "\n" "Examples\n" "\n" " # This is a common action template. It would invoke a script with\n" @@ -121,7 +131,20 @@ " target(my_wrapper_target_type, target_name) {\n" " forward_variables_from(invoker, \"*\")\n" " }\n" - " }\n"; + " }\n" + "\n" + " # A template that wraps another. It adds behavior based on one \n" + " # variable, and forwards all others to the nested target.\n" + " template(\"my_ios_test_app\") {\n" + " ios_test_app(target_name) {\n" + " forward_variables_from(invoker, \"*\", [\"test_bundle_name\"])\n" + " if (!defined(extra_substitutions)) {\n" + " extra_substitutions = []\n" + " }\n" + " extra_substitutions += [ \"BUNDLE_ID_TEST_NAME=$test_bundle_name\" " + "]\n" + " }\n" + " }\n"; // This function takes a ListNode rather than a resolved vector of values // both avoid copying the potentially-large source scope, and so the variables @@ -131,9 +154,9 @@ const ListNode* args_list, Err* err) { const std::vector<const ParseNode*>& args_vector = args_list->contents(); - if (args_vector.size() != 2) { + if (args_vector.size() != 2 && args_vector.size() != 3) { *err = Err(function, "Wrong number of arguments.", - "Expecting exactly two."); + "Expecting two or three arguments."); return Value(); } @@ -157,18 +180,40 @@ return Value(); Scope* source = value->scope_value(); + // Extract the exclusion list if defined. + std::set<std::string> exclusion_set; + if (args_vector.size() == 3) { + Value exclusion_value = args_vector[2]->Execute(scope, err); + if (err->has_error()) + return Value(); + + if (exclusion_value.type() != Value::LIST) { + *err = Err(exclusion_value, "Not a valid list of variables to exclude.", + "Expecting a list of strings."); + return Value(); + } + + for (const Value& cur : exclusion_value.list_value()) { + if (!cur.VerifyTypeIs(Value::STRING, err)) + return Value(); + + exclusion_set.insert(cur.string_value()); + } + } + // Extract the list. If all_values is not set, the what_value will be a list. Value what_value = args_vector[1]->Execute(scope, err); if (err->has_error()) return Value(); if (what_value.type() == Value::STRING) { if (what_value.string_value() == "*") { - ForwardAllValues(function, source, scope, err); + ForwardAllValues(function, source, scope, exclusion_set, err); return Value(); } } else { if (what_value.type() == Value::LIST) { - ForwardValuesFromList(source, scope, what_value.list_value(), err); + ForwardValuesFromList(source, scope, what_value.list_value(), + exclusion_set, err); return Value(); } }
diff --git a/tools/gn/function_forward_variables_from_unittest.cc b/tools/gn/function_forward_variables_from_unittest.cc index c3dd715..e5137a4 100644 --- a/tools/gn/function_forward_variables_from_unittest.cc +++ b/tools/gn/function_forward_variables_from_unittest.cc
@@ -32,6 +32,34 @@ setup.print_output().clear(); } +TEST(FunctionForwardVariablesFrom, ListWithExclusion) { + Scheduler scheduler; + TestWithScope setup; + + // Defines a template and copy the two x and y, and z values out. + TestParseInput input( + "template(\"a\") {\n" + " forward_variables_from(invoker, [\"x\", \"y\", \"z\"], [\"z\"])\n" + " assert(!defined(z))\n" // "z" should still be undefined. + " print(\"$target_name, $x, $y\")\n" + "}\n" + "a(\"target\") {\n" + " x = 1\n" + " y = 2\n" + " z = 3\n" + " print(\"$z\")\n" + "}\n"); + + ASSERT_FALSE(input.has_error()); + + Err err; + input.parsed()->Execute(setup.scope(), &err); + ASSERT_FALSE(err.has_error()) << err.message(); + + EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output()); + setup.print_output().clear(); +} + TEST(FunctionForwardVariablesFrom, ErrorCases) { Scheduler scheduler; TestWithScope setup; @@ -65,19 +93,61 @@ EXPECT_TRUE(err.has_error()); EXPECT_EQ("Not a valid list of variables to copy.", err.message()); - // Programmatic values should error. - TestParseInput prog( + // Type check the exclusion list. + TestParseInput invalid_exclusion_list( "template(\"c\") {\n" - " forward_variables_from(invoker, [\"root_out_dir\"])\n" + " forward_variables_from(invoker, \"*\", 42)\n" " print(\"$target_name\")\n" "}\n" "c(\"target\") {\n" "}\n"); + ASSERT_FALSE(invalid_exclusion_list.has_error()); + err = Err(); + invalid_exclusion_list.parsed()->Execute(setup.scope(), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Not a valid list of variables to exclude.", err.message()); + + // Programmatic values should error. + TestParseInput prog( + "template(\"d\") {\n" + " forward_variables_from(invoker, [\"root_out_dir\"])\n" + " print(\"$target_name\")\n" + "}\n" + "d(\"target\") {\n" + "}\n"); ASSERT_FALSE(prog.has_error()); err = Err(); prog.parsed()->Execute(setup.scope(), &err); EXPECT_TRUE(err.has_error()); EXPECT_EQ("This value can't be forwarded.", err.message()); + + // Not enough arguments. + TestParseInput not_enough_arguments( + "template(\"e\") {\n" + " forward_variables_from(invoker)\n" + " print(\"$target_name\")\n" + "}\n" + "e(\"target\") {\n" + "}\n"); + ASSERT_FALSE(not_enough_arguments.has_error()); + err = Err(); + not_enough_arguments.parsed()->Execute(setup.scope(), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Wrong number of arguments.", err.message()); + + // Too many arguments. + TestParseInput too_many_arguments( + "template(\"f\") {\n" + " forward_variables_from(invoker, \"*\", [], [])\n" + " print(\"$target_name\")\n" + "}\n" + "f(\"target\") {\n" + "}\n"); + ASSERT_FALSE(too_many_arguments.has_error()); + err = Err(); + too_many_arguments.parsed()->Execute(setup.scope(), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Wrong number of arguments.", err.message()); } TEST(FunctionForwardVariablesFrom, Star) { @@ -106,3 +176,33 @@ EXPECT_EQ("target, 1, 2\n", setup.print_output()); setup.print_output().clear(); } + + +TEST(FunctionForwardVariablesFrom, StarWithExclusion) { + Scheduler scheduler; + TestWithScope setup; + + // Defines a template and copy all values except z value. The "*" behavior + // should clobber existing variables with the same name. + TestParseInput input( + "template(\"a\") {\n" + " x = 1000000\n" // Should be clobbered. + " forward_variables_from(invoker, \"*\", [\"z\"])\n" + " print(\"$target_name, $x, $y\")\n" + "}\n" + "a(\"target\") {\n" + " x = 1\n" + " y = 2\n" + " z = 3\n" + " print(\"$z\")\n" + "}\n"); + + ASSERT_FALSE(input.has_error()); + + Err err; + input.parsed()->Execute(setup.scope(), &err); + ASSERT_FALSE(err.has_error()) << err.message(); + + EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output()); + setup.print_output().clear(); +}
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc index 2bf9dd4..dc22367 100644 --- a/tools/gn/scope.cc +++ b/tools/gn/scope.cc
@@ -25,6 +25,15 @@ } // namespace +// Defaults to all false, which are the things least likely to cause errors. +Scope::MergeOptions::MergeOptions() + : clobber_existing(false), + skip_private_vars(false), + mark_dest_used(false) { +} + +Scope::MergeOptions::~MergeOptions() { +} Scope::ProgrammaticProvider::~ProgrammaticProvider() { scope_->RemoveProvider(this); @@ -249,17 +258,23 @@ Err* err) const { // Values. for (const auto& pair : values_) { - if (options.skip_private_vars && IsPrivateVar(pair.first)) + const base::StringPiece& current_name = pair.first; + if (options.skip_private_vars && IsPrivateVar(current_name)) continue; // Skip this private var. + if (!options.excluded_values.empty() && + options.excluded_values.find(current_name.as_string()) != + options.excluded_values.end()) { + continue; // Skip this excluded value. + } const Value& new_value = pair.second.value; if (!options.clobber_existing) { - const Value* existing_value = dest->GetValue(pair.first); + const Value* existing_value = dest->GetValue(current_name); if (existing_value && new_value != *existing_value) { // Value present in both the source and the dest. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Value collision.", - "This " + desc_string + " contains \"" + pair.first.as_string() + + "This " + desc_string + " contains \"" + current_name.as_string() + "\""); err->AppendSubErr(Err(pair.second.value, "defined here.", "Which would clobber the one in your current scope")); @@ -269,23 +284,30 @@ return false; } } - dest->values_[pair.first] = pair.second; + dest->values_[current_name] = pair.second; if (options.mark_dest_used) - dest->MarkUsed(pair.first); + dest->MarkUsed(current_name); } // Target defaults are owning pointers. for (const auto& pair : target_defaults_) { + const std::string& current_name = pair.first; + if (!options.excluded_values.empty() && + options.excluded_values.find(current_name) != + options.excluded_values.end()) { + continue; // Skip the excluded value. + } + if (!options.clobber_existing) { - if (dest->GetTargetDefaults(pair.first)) { + if (dest->GetTargetDefaults(current_name)) { // TODO(brettw) it would be nice to know the origin of a // set_target_defaults so we can give locations for the colliding target // defaults. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Target defaults collision.", "This " + desc_string + " contains target defaults for\n" - "\"" + pair.first + "\" which would clobber one for the\n" + "\"" + current_name + "\" which would clobber one for the\n" "same target type in your current scope. It's unfortunate that I'm " "too stupid\nto tell you the location of where the target defaults " "were set. Usually\nthis happens in the BUILDCONFIG.gn file."); @@ -294,7 +316,7 @@ } // Be careful to delete any pointer we're about to clobber. - Scope** dest_scope = &dest->target_defaults_[pair.first]; + Scope** dest_scope = &dest->target_defaults_[current_name]; if (*dest_scope) delete *dest_scope; *dest_scope = new Scope(settings_); @@ -320,11 +342,17 @@ // Templates. for (const auto& pair : templates_) { - if (options.skip_private_vars && IsPrivateVar(pair.first)) + const std::string& current_name = pair.first; + if (options.skip_private_vars && IsPrivateVar(current_name)) continue; // Skip this private template. + if (!options.excluded_values.empty() && + options.excluded_values.find(current_name) != + options.excluded_values.end()) { + continue; // Skip the excluded value. + } if (!options.clobber_existing) { - const Template* existing_template = dest->GetTemplate(pair.first); + const Template* existing_template = dest->GetTemplate(current_name); // Since templates are refcounted, we can check if it's the same one by // comparing pointers. if (existing_template && pair.second.get() != existing_template) { @@ -333,7 +361,7 @@ std::string desc_string(desc_for_err); *err = Err(node_for_err, "Template collision.", "This " + desc_string + " contains a template \"" + - pair.first + "\""); + current_name + "\""); err->AppendSubErr(Err(pair.second->GetDefinitionRange(), "defined here.", "Which would clobber the one in your current scope")); @@ -346,7 +374,7 @@ } // Be careful to delete any pointer we're about to clobber. - dest->templates_[pair.first] = pair.second; + dest->templates_[current_name] = pair.second; } return true;
diff --git a/tools/gn/scope.h b/tools/gn/scope.h index 7b32941..2554366a 100644 --- a/tools/gn/scope.h +++ b/tools/gn/scope.h
@@ -65,12 +65,8 @@ // Options for configuring scope merges. struct MergeOptions { - // Defaults to all false, which are the things least likely to cause errors. - MergeOptions() - : clobber_existing(false), - skip_private_vars(false), - mark_dest_used(false) { - } + MergeOptions(); + ~MergeOptions(); // When set, all existing avlues in the destination scope will be // overwritten. @@ -92,6 +88,9 @@ // import, for example, or files that don't need a variable from the .gni // file will throw an error. bool mark_dest_used; + + // When set, those variables are not merged. + std::set<std::string> excluded_values; }; // Creates an empty toplevel scope.
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 459b87b..79814e6 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -31,6 +31,7 @@ #include "tools/gn/tokenizer.h" #include "tools/gn/trace.h" #include "tools/gn/value.h" +#include "tools/gn/value_extractors.h" #if defined(OS_WIN) #include <windows.h> @@ -655,21 +656,13 @@ const Value* check_targets_value = dotfile_scope_.GetValue("check_targets", true); if (check_targets_value) { - // Fill the list of targets to check. - if (!check_targets_value->VerifyTypeIs(Value::LIST, &err)) { + check_patterns_.reset(new std::vector<LabelPattern>); + ExtractListOfLabelPatterns(*check_targets_value, current_dir, + check_patterns_.get(), &err); + if (err.has_error()) { err.PrintToStdout(); return false; } - - check_patterns_.reset(new std::vector<LabelPattern>); - for (const auto& item : check_targets_value->list_value()) { - check_patterns_->push_back( - LabelPattern::GetPattern(current_dir, item, &err)); - if (err.has_error()) { - err.PrintToStdout(); - return false; - } - } } // Fill exec_script_whitelist.
diff --git a/tools/gn/target.cc b/tools/gn/target.cc index 905ee4f..7dd1921 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc
@@ -129,6 +129,61 @@ return false; } +// check_this indicates if the given target should be matched against the +// patterns. It should be set to false for the first call since assert_no_deps +// shouldn't match the target itself. +// +// visited should point to an empty set, this will be used to prevent +// multiple visits. +// +// *failure_path_str will be filled with a string describing the path of the +// dependency failure, and failure_pattern will indicate the pattern in +// assert_no that matched the target. +// +// Returns true if everything is OK. failure_path_str and failure_pattern_index +// will be unchanged in this case. +bool RecursiveCheckAssertNoDeps(const Target* target, + bool check_this, + const std::vector<LabelPattern>& assert_no, + std::set<const Target*>* visited, + std::string* failure_path_str, + const LabelPattern** failure_pattern) { + static const char kIndentPath[] = " "; + + if (visited->find(target) != visited->end()) + return true; // Already checked this target. + visited->insert(target); + + if (check_this) { + // Check this target against the given list of patterns. + for (const LabelPattern& pattern : assert_no) { + if (pattern.Matches(target->label())) { + // Found a match. + *failure_pattern = &pattern; + *failure_path_str = + kIndentPath + target->label().GetUserVisibleName(false); + return false; + } + } + } + + // Recursively check dependencies. + for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) { + if (pair.ptr->output_type() == Target::EXECUTABLE) + continue; + if (!RecursiveCheckAssertNoDeps(pair.ptr, true, assert_no, visited, + failure_path_str, failure_pattern)) { + // To reconstruct the path, prepend the current target to the error. + std::string prepend_path = + kIndentPath + target->label().GetUserVisibleName(false) + " ->\n"; + failure_path_str->insert(0, prepend_path); + return false; + } + } + + return true; +} + } // namespace Target::Target(const Settings* settings, const Label& label) @@ -234,6 +289,8 @@ return false; if (!CheckNoNestedStaticLibs(err)) return false; + if (!CheckAssertNoDeps(err)) + return false; CheckSourcesGenerated(); } @@ -604,6 +661,27 @@ return true; } +bool Target::CheckAssertNoDeps(Err* err) const { + if (assert_no_deps_.empty()) + return true; + + std::set<const Target*> visited; + std::string failure_path_str; + const LabelPattern* failure_pattern = nullptr; + + if (!RecursiveCheckAssertNoDeps(this, false, assert_no_deps_, &visited, + &failure_path_str, &failure_pattern)) { + *err = Err(defined_from(), "assert_no_deps failed.", + label().GetUserVisibleName(false) + + " has an assert_no_deps entry:\n " + + failure_pattern->Describe() + + "\nwhich fails for the dependency path:\n" + + failure_path_str); + return false; + } + return true; +} + void Target::CheckSourcesGenerated() const { // Checks that any inputs or sources to this target that are in the build // directory are generated by a target that this one transitively depends on
diff --git a/tools/gn/target.h b/tools/gn/target.h index cbdab357..18e5fb8 100644 --- a/tools/gn/target.h +++ b/tools/gn/target.h
@@ -16,6 +16,7 @@ #include "tools/gn/config_values.h" #include "tools/gn/inherited_libraries.h" #include "tools/gn/item.h" +#include "tools/gn/label_pattern.h" #include "tools/gn/label_ptr.h" #include "tools/gn/lib_file.h" #include "tools/gn/ordered_set.h" @@ -209,6 +210,13 @@ return recursive_hard_deps_; } + std::vector<LabelPattern>& assert_no_deps() { + return assert_no_deps_; + } + const std::vector<LabelPattern>& assert_no_deps() const { + return assert_no_deps_; + } + // The toolchain is only known once this target is resolved (all if its // dependencies are known). They will be null until then. Generally, this can // only be used during target writing. @@ -284,6 +292,7 @@ bool CheckVisibility(Err* err) const; bool CheckTestonly(Err* err) const; bool CheckNoNestedStaticLibs(Err* err) const; + bool CheckAssertNoDeps(Err* err) const; void CheckSourcesGenerated() const; void CheckSourceGenerated(const SourceFile& source) const; @@ -324,6 +333,8 @@ // target is marked resolved. This will not include the current target. std::set<const Target*> recursive_hard_deps_; + std::vector<LabelPattern> assert_no_deps_; + // Used for all binary targets. The precompiled header values in this struct // will be resolved to the ones to use for this target, if precompiled // headers are used.
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc index 3734ea9c..b1ed1ea3 100644 --- a/tools/gn/target_generator.cc +++ b/tools/gn/target_generator.cc
@@ -50,6 +50,9 @@ if (!FillTestonly()) return; + if (!FillAssertNoDeps()) + return; + if (!Visibility::FillItemVisibility(target_, scope_, err_)) return; @@ -266,6 +269,15 @@ return true; } +bool TargetGenerator::FillAssertNoDeps() { + const Value* value = scope_->GetValue(variables::kAssertNoDeps, true); + if (value) { + return ExtractListOfLabelPatterns(*value, scope_->GetSourceDir(), + &target_->assert_no_deps(), err_); + } + return true; +} + bool TargetGenerator::FillOutputs(bool allow_substitutions) { const Value* value = scope_->GetValue(variables::kOutputs, true); if (!value)
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h index 1fd055b1..4fa51f6 100644 --- a/tools/gn/target_generator.h +++ b/tools/gn/target_generator.h
@@ -70,6 +70,7 @@ bool FillData(); bool FillDependencies(); // Includes data dependencies. bool FillTestonly(); + bool FillAssertNoDeps(); // Reads configs/deps from the given var name, and uses the given setting on // the target to save them.
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc index c59f44c..c99ebe8 100644 --- a/tools/gn/target_unittest.cc +++ b/tools/gn/target_unittest.cc
@@ -668,3 +668,58 @@ " source: //pcs2.cc", err.help_text()); } + +TEST(Target, AssertNoDeps) { + TestWithScope setup; + Err err; + + // A target. + TestTarget a(setup, "//a", Target::SHARED_LIBRARY); + ASSERT_TRUE(a.OnResolved(&err)); + + // B depends on A and has an assert_no_deps for a random dir. + TestTarget b(setup, "//b", Target::SHARED_LIBRARY); + b.private_deps().push_back(LabelTargetPair(&a)); + b.assert_no_deps().push_back(LabelPattern( + LabelPattern::RECURSIVE_DIRECTORY, SourceDir("//disallowed/"), + std::string(), Label())); + ASSERT_TRUE(b.OnResolved(&err)); + + LabelPattern disallow_a(LabelPattern::RECURSIVE_DIRECTORY, SourceDir("//a/"), + std::string(), Label()); + + // C depends on B and disallows depending on A. This should fail. + TestTarget c(setup, "//c", Target::EXECUTABLE); + c.private_deps().push_back(LabelTargetPair(&b)); + c.assert_no_deps().push_back(disallow_a); + ASSERT_FALSE(c.OnResolved(&err)); + + // Validate the error message has the proper path. + EXPECT_EQ( + "//c:c has an assert_no_deps entry:\n" + " //a/*\n" + "which fails for the dependency path:\n" + " //c:c ->\n" + " //b:b ->\n" + " //a:a", + err.help_text()); + err = Err(); + + // Add an intermediate executable with: exe -> b -> a + TestTarget exe(setup, "//exe", Target::EXECUTABLE); + exe.private_deps().push_back(LabelTargetPair(&b)); + ASSERT_TRUE(exe.OnResolved(&err)); + + // D depends on the executable and disallows depending on A. Since there is + // an intermediate executable, this should be OK. + TestTarget d(setup, "//d", Target::EXECUTABLE); + d.private_deps().push_back(LabelTargetPair(&exe)); + d.assert_no_deps().push_back(disallow_a); + ASSERT_TRUE(d.OnResolved(&err)); + + // A2 disallows depending on anything in its own directory, but the + // assertions should not match the target itself so this should be OK. + TestTarget a2(setup, "//a:a2", Target::EXECUTABLE); + a2.assert_no_deps().push_back(disallow_a); + ASSERT_TRUE(a2.OnResolved(&err)); +}
diff --git a/tools/gn/value_extractors.cc b/tools/gn/value_extractors.cc index 23c5a272..ff009ce 100644 --- a/tools/gn/value_extractors.cc +++ b/tools/gn/value_extractors.cc
@@ -144,6 +144,17 @@ const Label& current_toolchain; }; +struct LabelPatternResolver { + LabelPatternResolver(const SourceDir& current_dir_in) + : current_dir(current_dir_in) { + } + bool operator()(const Value& v, LabelPattern* out, Err* err) const { + *out = LabelPattern::GetPattern(current_dir, v, err); + return !err->has_error(); + } + const SourceDir& current_dir; +}; + } // namespace bool ExtractListOfStringValues(const Value& value, @@ -236,3 +247,11 @@ RelativeFileConverter converter(build_settings, current_dir); return converter(value, file, err); } + +bool ExtractListOfLabelPatterns(const Value& value, + const SourceDir& current_dir, + std::vector<LabelPattern>* patterns, + Err* err) { + return ListValueExtractor(value, patterns, err, + LabelPatternResolver(current_dir)); +}
diff --git a/tools/gn/value_extractors.h b/tools/gn/value_extractors.h index 06d64ce..1e426502 100644 --- a/tools/gn/value_extractors.h +++ b/tools/gn/value_extractors.h
@@ -15,6 +15,7 @@ class BuildSettings; class Err; class Label; +class LabelPattern; class SourceDir; class SourceFile; class Value; @@ -80,4 +81,9 @@ SourceFile* file, Err* err); +bool ExtractListOfLabelPatterns(const Value& value, + const SourceDir& current_dir, + std::vector<LabelPattern>* patterns, + Err* err); + #endif // TOOLS_GN_VALUE_EXTRACTORS_H_
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc index a835b22..c88a182f 100644 --- a/tools/gn/variables.cc +++ b/tools/gn/variables.cc
@@ -391,6 +391,49 @@ "\n" " See also \"gn help action\" and \"gn help action_foreach\".\n"; +const char kAssertNoDeps[] = "assert_no_deps"; +const char kAssertNoDeps_HelpShort[] = + "assert_no_deps: [label pattern list] Ensure no deps on these targets."; +const char kAssertNoDeps_Help[] = + "assert_no_deps: Ensure no deps on these targets.\n" + "\n" + " A list of label patterns.\n" + "\n" + " This list is a list of patterns that must not match any of the\n" + " transitive dependencies of the target. These include all public,\n" + " private, and data dependencies, and cross shared library boundaries.\n" + " This allows you to express that undesirable code isn't accidentally\n" + " added to downstream dependencies in a way that might otherwise be\n" + " difficult to notice.\n" + "\n" + " Checking does not cross executable boundaries. If a target depends on\n" + " an executable, it's assumed that the executable is a tool that is\n" + " producing part of the build rather than something that is linked and\n" + " distributed. This allows assert_no_deps to express what is distributed\n" + " in the final target rather than depend on the internal build steps\n" + " (which may include non-distributable code).\n" + "\n" + " See \"gn help label_pattern\" for the format of the entries in the\n" + " list. These patterns allow blacklisting individual targets or whole\n" + " directory hierarchies.\n" + "\n" + " Sometimes it is desirable to enforce that many targets have no\n" + " dependencies on a target or set of targets. One efficient way to\n" + " express this is to create a group with the assert_no_deps rule on\n" + " it, and make that group depend on all targets you want to apply that\n" + " assertion to.\n" + "\n" + "Example\n" + "\n" + " executable(\"doom_melon\") {\n" + " deps = [ \"//foo:bar\" ]\n" + " ...\n" + " assert_no_deps = [\n" + " \"//evil/*\", # Don't link any code from the evil directory.\n" + " \"//foo:test_support\", # This target is also disallowed.\n" + " ]\n" + " }\n"; + const char kCflags[] = "cflags"; const char kCflags_HelpShort[] = "cflags: [string list] Flags passed to all C compiler variants."; @@ -1400,6 +1443,7 @@ INSERT_VARIABLE(AllowCircularIncludesFrom) INSERT_VARIABLE(Args) INSERT_VARIABLE(Asmflags) + INSERT_VARIABLE(AssertNoDeps) INSERT_VARIABLE(Cflags) INSERT_VARIABLE(CflagsC) INSERT_VARIABLE(CflagsCC)
diff --git a/tools/gn/variables.h b/tools/gn/variables.h index d02d2c6f..ee68bd52 100644 --- a/tools/gn/variables.h +++ b/tools/gn/variables.h
@@ -87,6 +87,10 @@ extern const char kAsmflags_HelpShort[]; extern const char* kAsmflags_Help; +extern const char kAssertNoDeps[]; +extern const char kAssertNoDeps_HelpShort[]; +extern const char kAssertNoDeps_Help[]; + extern const char kCflags[]; extern const char kCflags_HelpShort[]; extern const char* kCflags_Help;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b5a898b6..63662ee 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -10362,6 +10362,9 @@ </histogram> <histogram name="Enterprise.SystemLogPIILeak" enum="SystemLogPIIType"> + <obsolete> + Deprecated and removed from code as of 01/2016. + </obsolete> <owner>pbond@chromium.org</owner> <summary> Events for counting sensitive data occurrences in system logs to upload. @@ -79678,6 +79681,9 @@ </enum> <enum name="SystemLogPIIType" type="int"> + <obsolete> + Deprecated and removed from code as of 01/2016. + </obsolete> <int value="0" label="Email address"/> <int value="1" label="IP address"/> <int value="2" label="Web URL"/>
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt index c53e889..b3ced04f 100644 --- a/tools/valgrind/memcheck/suppressions.txt +++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3457,3 +3457,31 @@ fun:_ZN5blink11WebViewImpl12setMainFrameEPNS_8WebFrameE fun:_ZN10extensions14ScopedWebFrameC1Ev } +{ + bug_581092_a + Memcheck:Leak + ... + fun:_ZN5blink15ContextFeatures13defaultSwitchEv + fun:_ZN5blink8DocumentC2ERKNS_12DocumentInitEh + fun:_ZN5blink12HTMLDocumentC1ERKNS_12DocumentInitEh + fun:_ZN5blink12HTMLDocument6createERKNS_12DocumentInitE + fun:_ZN5blink17DOMImplementation14createDocumentERKN3WTF6StringERKNS_12DocumentInitEb + fun:_ZN5blink14LocalDOMWindow14createDocumentERKN3WTF6StringERKNS_12DocumentInitEb + fun:_ZN5blink14LocalDOMWindow18installNewDocumentERKN3WTF6StringERKNS_12DocumentInitEb + fun:_ZN5blink14DocumentLoader15createWriterForEPKNS_* +} +{ + bug_581092_b + Memcheck:Leak + fun:_Znw* + fun:_ZN5blink26RefCountedGarbageCollectedINS_15StyleFilterDataEE13makeKeepAliveEv + fun:_ZN5blink26RefCountedGarbageCollectedINS_15StyleFilterDataEE3refEv + ... + fun:_ZN5blink7DataRefINS_15StyleFilterDataEE4initEv + ... + fun:_ZN5blink13ComputedStyle6createEv + fun:_ZN5blink13StyleResolver16styleForDocumentERNS_8DocumentE + fun:_ZN5blink8Document6attachERKNS_4Node13AttachContextE + fun:_ZN5blink14LocalDOMWindow18installNewDocumentERKN3WTF6StringERKNS_12DocumentInitEb + fun:_ZN5blink14DocumentLoader15createWriterForEPKNS_* +}
diff --git a/ui/arc/notification/arc_notification_item.cc b/ui/arc/notification/arc_notification_item.cc index 694f41bd..48d386885 100644 --- a/ui/arc/notification/arc_notification_item.cc +++ b/ui/arc/notification/arc_notification_item.cc
@@ -60,6 +60,11 @@ item_->Click(); } + void ButtonClick(int button_index) override { + if (item_) + item_->ButtonClick(button_index); + } + private: // The destructor is private since this class is ref-counted. ~ArcNotificationDelegate() override {} @@ -125,6 +130,11 @@ DCHECK(ArcNotificationType_IsValidValue(data.type)) << "Unsupported notification type: " << data.type; + for (size_t i = 0; i < data.buttons.size(); i++) { + rich_data.buttons.push_back(message_center::ButtonInfo( + base::UTF8ToUTF16(data.buttons.at(i)->label.get()))); + } + // The identifier of the notifier, which is used to distinguish the notifiers // in the message center. message_center::NotifierId notifier_id( @@ -179,6 +189,11 @@ manager_->SendNotificationClickedOnChrome(notification_key_); } +void ArcNotificationItem::ButtonClick(int button_index) { + manager_->SendNotificationButtonClickedOnChrome( + notification_key_, button_index); +} + void ArcNotificationItem::OnImageDecoded(const SkBitmap& bitmap) { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/ui/arc/notification/arc_notification_item.h b/ui/arc/notification/arc_notification_item.h index 90247168..ee8e773 100644 --- a/ui/arc/notification/arc_notification_item.h +++ b/ui/arc/notification/arc_notification_item.h
@@ -35,6 +35,7 @@ // Methods called from ArcNotificationItemDelegate: void Close(bool by_user); void Click(); + void ButtonClick(int button_index); private: void OnImageDecoded(const SkBitmap& bitmap);
diff --git a/ui/arc/notification/arc_notification_manager.cc b/ui/arc/notification/arc_notification_manager.cc index a5692d54..11e7b47 100644 --- a/ui/arc/notification/arc_notification_manager.cc +++ b/ui/arc/notification/arc_notification_manager.cc
@@ -87,4 +87,39 @@ ->SendNotificationEventToAndroid(key, ArcNotificationEvent::BODY_CLICKED); } +void ArcNotificationManager::SendNotificationButtonClickedOnChrome( + const std::string& key, int button_index) { + if (!items_.contains(key)) { + VLOG(3) << "Chrome requests to fire a click event on notification (key: " + << key << "), but it is gone."; + return; + } + + arc::ArcNotificationEvent command; + switch (button_index) { + case 0: + command = ArcNotificationEvent::BUTTON1_CLICKED; + break; + case 1: + command = ArcNotificationEvent::BUTTON2_CLICKED; + break; + case 2: + command = ArcNotificationEvent::BUTTON3_CLICKED; + break; + case 3: + command = ArcNotificationEvent::BUTTON4_CLICKED; + break; + case 4: + command = ArcNotificationEvent::BUTTON5_CLICKED; + break; + default: + VLOG(3) << "Invalid button index (key: " << key << ", index: " << + button_index << ")."; + return; + } + + arc_bridge_service() + ->notifications_instance()->SendNotificationEventToAndroid(key, command); +} + } // namespace arc
diff --git a/ui/arc/notification/arc_notification_manager.h b/ui/arc/notification/arc_notification_manager.h index f463fa6..1d46b8f 100644 --- a/ui/arc/notification/arc_notification_manager.h +++ b/ui/arc/notification/arc_notification_manager.h
@@ -37,6 +37,8 @@ // Methods called from ArcNotificationItem: void SendNotificationRemovedFromChrome(const std::string& key); void SendNotificationClickedOnChrome(const std::string& key); + void SendNotificationButtonClickedOnChrome( + const std::string& key, int button_index); private: const AccountId main_profile_id_;
diff --git a/ui/base/template_expressions.cc b/ui/base/template_expressions.cc index 1d63e0c3..afddf5e0 100644 --- a/ui/base/template_expressions.cc +++ b/ui/base/template_expressions.cc
@@ -8,29 +8,36 @@ #include "base/logging.h" +namespace { +const char kLeader[] = "$i18n{"; +const size_t kLeaderSize = arraysize(kLeader) - 1; +const char kTail[] = "}"; +const size_t kTailSize = arraysize(kTail) - 1; +} // namespace + namespace ui { std::string ReplaceTemplateExpressions( base::StringPiece format_string, - const std::map<base::StringPiece, std::string>& substitutions) { + const TemplateReplacements& substitutions) { std::string formatted; const size_t kValueLengthGuess = 16; formatted.reserve(format_string.length() + substitutions.size() * kValueLengthGuess); base::StringPiece::const_iterator i = format_string.begin(); while (i < format_string.end()) { - if (*i == '$' && i + 2 < format_string.end() && i[1] == '{' && - i[2] != '}') { - size_t key_start = i + strlen("${") - format_string.begin(); - size_t key_length = format_string.find('}', key_start); + if (base::StringPiece(i).starts_with(kLeader)) { + size_t key_start = i + kLeaderSize - format_string.begin(); + size_t key_length = format_string.find(kTail, key_start); if (key_length == base::StringPiece::npos) - NOTREACHED() << "TemplateExpression missing ending brace '}'"; + NOTREACHED() << "TemplateExpression missing ending tag"; key_length -= key_start; - base::StringPiece key(format_string.begin() + key_start, key_length); + std::string key(format_string.begin() + key_start, key_length); + DCHECK(!key.empty()); const auto& replacement = substitutions.find(key); if (replacement != substitutions.end()) { formatted.append(replacement->second); - i += strlen("${") + key_length + strlen("}"); + i += kLeaderSize + key_length + kTailSize; continue; } else { NOTREACHED() << "TemplateExpression key not found: " << key;
diff --git a/ui/base/template_expressions.h b/ui/base/template_expressions.h index ff14ee1..a8ac908b 100644 --- a/ui/base/template_expressions.h +++ b/ui/base/template_expressions.h
@@ -16,12 +16,15 @@ namespace ui { +// Map of strings for template replacement in |ReplaceTemplateExpressions|. +typedef std::map<const std::string, std::string> TemplateReplacements; + // Replace ${foo} in the format string with the value for the foo key in // |subst|. If the key is not found in the |substitutions| that item will // be unaltered. UI_BASE_EXPORT std::string ReplaceTemplateExpressions( base::StringPiece format_string, - const std::map<base::StringPiece, std::string>& substitutions); + const TemplateReplacements& substitutions); } // namespace ui
diff --git a/ui/base/template_expressions_unittest.cc b/ui/base/template_expressions_unittest.cc index b56a5e7..947f2539 100644 --- a/ui/base/template_expressions_unittest.cc +++ b/ui/base/template_expressions_unittest.cc
@@ -9,27 +9,26 @@ namespace ui { TEST(TemplateExpressionsTest, ReplaceTemplateExpressionsPieces) { - std::map<base::StringPiece, std::string> substitutions; + TemplateReplacements substitutions; substitutions["test"] = "word"; substitutions["5"] = "number"; - EXPECT_EQ("${}", ReplaceTemplateExpressions("${}", substitutions)); EXPECT_EQ("", ReplaceTemplateExpressions("", substitutions)); - EXPECT_EQ("word", ReplaceTemplateExpressions("${test}", substitutions)); - EXPECT_EQ("number ", ReplaceTemplateExpressions("${5} ", substitutions)); - EXPECT_EQ( - "multiple: word, number.", - ReplaceTemplateExpressions("multiple: ${test}, ${5}.", substitutions)); + EXPECT_EQ("word", ReplaceTemplateExpressions("$i18n{test}", substitutions)); + EXPECT_EQ("number ", ReplaceTemplateExpressions("$i18n{5} ", substitutions)); + EXPECT_EQ("multiple: word, number.", + ReplaceTemplateExpressions("multiple: $i18n{test}, $i18n{5}.", + substitutions)); } TEST(TemplateExpressionsTest, ReplaceTemplateExpressionsConsecutiveDollarSignsPieces) { - std::map<base::StringPiece, std::string> substitutions; + TemplateReplacements substitutions; substitutions["a"] = "x"; EXPECT_EQ("$ $$ $$$", ReplaceTemplateExpressions("$ $$ $$$", substitutions)); - EXPECT_EQ("$x", ReplaceTemplateExpressions("$${a}", substitutions)); - EXPECT_EQ("$$x", ReplaceTemplateExpressions("$$${a}", substitutions)); - EXPECT_EQ("$12", ReplaceTemplateExpressions("$12", substitutions)); + EXPECT_EQ("$x", ReplaceTemplateExpressions("$$i18n{a}", substitutions)); + EXPECT_EQ("$$x", ReplaceTemplateExpressions("$$$i18n{a}", substitutions)); + EXPECT_EQ("$i18n12", ReplaceTemplateExpressions("$i18n12", substitutions)); } } // namespace ui
diff --git a/ui/base/webui/web_ui_util.cc b/ui/base/webui/web_ui_util.cc index d9c1d76..e83ea68 100644 --- a/ui/base/webui/web_ui_util.cc +++ b/ui/base/webui/web_ui_util.cc
@@ -123,7 +123,7 @@ } std::string GetWebUiCssTextDefaults(const std::string& css_template) { - std::map<base::StringPiece, std::string> placeholders; + ui::TemplateReplacements placeholders; placeholders["textDirection"] = GetTextDirection(); placeholders["fontFamily"] = GetFontFamily(); placeholders["fontSize"] = GetFontSize();
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index dff25a6..05dfaaa 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -601,12 +601,11 @@ default: return DID_NOT_HANDLE; } - } else { - cc::InputHandlerScrollResult scroll_result = - input_handler_->ScrollBy(&scroll_state); - HandleOverscroll(scroll_point, scroll_result); - return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT; } + cc::InputHandlerScrollResult scroll_result = + input_handler_->ScrollBy(&scroll_state); + HandleOverscroll(scroll_point, scroll_result); + return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT; } InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollEnd(
diff --git a/ui/views/animation/button_ink_drop_delegate.cc b/ui/views/animation/button_ink_drop_delegate.cc index 2fa6000..40172ab 100644 --- a/ui/views/animation/button_ink_drop_delegate.cc +++ b/ui/views/animation/button_ink_drop_delegate.cc
@@ -43,9 +43,24 @@ ink_drop_animation_controller_->AnimateToState(state); } +void ButtonInkDropDelegate::SetHovered(bool is_hovered) { + ink_drop_animation_controller_->SetHovered(is_hovered); +} + //////////////////////////////////////////////////////////////////////////////// // ui::EventHandler: +void ButtonInkDropDelegate::OnMouseEvent(ui::MouseEvent* event) { + switch (event->type()) { + case ui::ET_MOUSE_ENTERED: + case ui::ET_MOUSE_EXITED: + SetHovered(ink_drop_host_->ShouldShowInkDropHover()); + break; + default: + return; + } +} + void ButtonInkDropDelegate::OnGestureEvent(ui::GestureEvent* event) { InkDropState current_ink_drop_state = ink_drop_animation_controller_->GetInkDropState();
diff --git a/ui/views/animation/button_ink_drop_delegate.h b/ui/views/animation/button_ink_drop_delegate.h index 2e8798da..dc4ecdce 100644 --- a/ui/views/animation/button_ink_drop_delegate.h +++ b/ui/views/animation/button_ink_drop_delegate.h
@@ -35,8 +35,10 @@ int small_corner_radius) override; void OnLayout() override; void OnAction(InkDropState state) override; + void SetHovered(bool is_hovered) override; // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override; void OnGestureEvent(ui::GestureEvent* event) override; private:
diff --git a/ui/views/animation/ink_drop_animation.h b/ui/views/animation/ink_drop_animation.h index abcd48c..6abc23b 100644 --- a/ui/views/animation/ink_drop_animation.h +++ b/ui/views/animation/ink_drop_animation.h
@@ -11,7 +11,6 @@ #include "base/time/time.h" #include "ui/compositor/layer_animator.h" #include "ui/gfx/geometry/size.h" -#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/transform.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/views_export.h"
diff --git a/ui/views/animation/ink_drop_animation_controller.h b/ui/views/animation/ink_drop_animation_controller.h index d4d4fce..993c852 100644 --- a/ui/views/animation/ink_drop_animation_controller.h +++ b/ui/views/animation/ink_drop_animation_controller.h
@@ -21,8 +21,8 @@ namespace views { -// Pure virtual base class that manages an ink drop animation's lifetime and -// state. +// Pure virtual base class that manages the lifetime and state of an ink drop +// animation as well as visual hover state feedback. class VIEWS_EXPORT InkDropAnimationController { public: virtual ~InkDropAnimationController() {} @@ -33,6 +33,12 @@ // Animates from the current InkDropState to |ink_drop_state|. virtual void AnimateToState(InkDropState ink_drop_state) = 0; + // Enables or disables the hover state. + virtual void SetHovered(bool is_hovered) = 0; + + // Returns true if the hover state is enabled. + virtual bool IsHovered() const = 0; + virtual gfx::Size GetInkDropLargeSize() const = 0; // Sets the different sizes of the ink drop.
diff --git a/ui/views/animation/ink_drop_animation_controller_factory.cc b/ui/views/animation/ink_drop_animation_controller_factory.cc index d03593c..f1f7825 100644 --- a/ui/views/animation/ink_drop_animation_controller_factory.cc +++ b/ui/views/animation/ink_drop_animation_controller_factory.cc
@@ -27,6 +27,8 @@ // InkDropAnimationController: InkDropState GetInkDropState() const override; void AnimateToState(InkDropState state) override; + void SetHovered(bool is_hovered) override; + bool IsHovered() const override; gfx::Size GetInkDropLargeSize() const override; void SetInkDropSize(const gfx::Size& large_size, int large_corner_radius, @@ -35,10 +37,15 @@ void SetInkDropCenter(const gfx::Point& center_point) override; private: + // Tracks whether the ink drop is hovered or not. This is used to ensure that + // this behaves like all other InkDropAnimationController implementations. + bool is_hovered_; + DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerStub); }; -InkDropAnimationControllerStub::InkDropAnimationControllerStub() {} +InkDropAnimationControllerStub::InkDropAnimationControllerStub() + : is_hovered_(false) {} InkDropAnimationControllerStub::~InkDropAnimationControllerStub() {} @@ -46,7 +53,17 @@ return InkDropState::HIDDEN; } -void InkDropAnimationControllerStub::AnimateToState(InkDropState state) {} +void InkDropAnimationControllerStub::AnimateToState(InkDropState state) { + SetHovered(false); +} + +void InkDropAnimationControllerStub::SetHovered(bool is_hovered) { + is_hovered_ = is_hovered; +} + +bool InkDropAnimationControllerStub::IsHovered() const { + return is_hovered_; +} gfx::Size InkDropAnimationControllerStub::GetInkDropLargeSize() const { return gfx::Size();
diff --git a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc index 6fa3324..a00a347 100644 --- a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc +++ b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc
@@ -4,12 +4,17 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/timer/timer.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/test/material_design_controller_test_api.h" #include "ui/compositor/scoped_animation_duration_scale_mode.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_animation_controller_impl.h" #include "ui/views/animation/ink_drop_host.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/animation/test/test_ink_drop_host.h" @@ -17,7 +22,8 @@ namespace views { class InkDropAnimationControllerFactoryTest - : public testing::TestWithParam<ui::MaterialDesignController::Mode> { + : public testing::TestWithParam< + testing::tuple<ui::MaterialDesignController::Mode>> { public: InkDropAnimationControllerFactoryTest(); ~InkDropAnimationControllerFactoryTest(); @@ -31,8 +37,14 @@ scoped_ptr<InkDropAnimationController> ink_drop_animation_controller_; private: + // Extracts and returns the material design mode from the test parameters. + ui::MaterialDesignController::Mode GetMaterialMode() const; + scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + // Required by base::Timer's. + scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; + DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerFactoryTest); }; @@ -42,7 +54,7 @@ // initialize and cache the mode. This ensures that these tests will run from // a non-initialized state. ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); - ui::test::MaterialDesignControllerTestAPI::SetMode(GetParam()); + ui::test::MaterialDesignControllerTestAPI::SetMode(GetMaterialMode()); ink_drop_animation_controller_.reset( InkDropAnimationControllerFactory::CreateInkDropAnimationController( &test_ink_drop_host_) @@ -52,6 +64,20 @@ zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); + + switch (GetMaterialMode()) { + case ui::MaterialDesignController::NON_MATERIAL: + break; + case ui::MaterialDesignController::MATERIAL_NORMAL: + case ui::MaterialDesignController::MATERIAL_HYBRID: + // The Timer's used by the InkDropAnimationControllerImpl class require a + // base::ThreadTaskRunnerHandle instance. + scoped_refptr<base::TestMockTimeTaskRunner> task_runner( + new base::TestMockTimeTaskRunner); + thread_task_runner_handle_.reset( + new base::ThreadTaskRunnerHandle(task_runner)); + break; + } } InkDropAnimationControllerFactoryTest:: @@ -59,13 +85,19 @@ ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); } +ui::MaterialDesignController::Mode +InkDropAnimationControllerFactoryTest::GetMaterialMode() const { + return testing::get<0>(GetParam()); +} + // Note: First argument is optional and intentionally left blank. // (it's a prefix for the generated test cases) INSTANTIATE_TEST_CASE_P( , InkDropAnimationControllerFactoryTest, testing::Values(ui::MaterialDesignController::NON_MATERIAL, - ui::MaterialDesignController::MATERIAL_NORMAL)); + ui::MaterialDesignController::MATERIAL_NORMAL, + ui::MaterialDesignController::MATERIAL_HYBRID)); TEST_P(InkDropAnimationControllerFactoryTest, VerifyAllInkDropLayersRemovedAfterDestruction) { @@ -79,6 +111,13 @@ ink_drop_animation_controller_->GetInkDropState()); } +TEST_P(InkDropAnimationControllerFactoryTest, HoveredStateAfterAnimateToState) { + ink_drop_animation_controller_->SetHovered(true); + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + + EXPECT_FALSE(ink_drop_animation_controller_->IsHovered()); +} + TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickAction) { ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); ink_drop_animation_controller_->AnimateToState(InkDropState::QUICK_ACTION);
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.cc b/ui/views/animation/ink_drop_animation_controller_impl.cc index 74d681d8d6..2035866 100644 --- a/ui/views/animation/ink_drop_animation_controller_impl.cc +++ b/ui/views/animation/ink_drop_animation_controller_impl.cc
@@ -4,19 +4,54 @@ #include "ui/views/animation/ink_drop_animation_controller_impl.h" +#include "base/timer/timer.h" +#include "ui/compositor/layer.h" #include "ui/views/animation/ink_drop_animation.h" #include "ui/views/animation/ink_drop_host.h" +#include "ui/views/animation/ink_drop_hover.h" namespace views { +namespace { + +// The duration, in milliseconds, of the hover state fade in animation when it +// is triggered by user input. +const int kHoverFadeInFromUserInputDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade out animation when it +// is triggered by user input. +const int kHoverFadeOutFromUserInputDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade in animation when it +// is triggered by an ink drop ripple animation ending. +const int kHoverFadeInAfterAnimationDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade out animation when it +// is triggered by an ink drop ripple animation starting. +const int kHoverFadeOutBeforeAnimationDurationInMs = 0; + +// The amount of time in milliseconds that |hover_| should delay after a ripple +// animation before fading in. +const int kHoverFadeInAfterAnimationDelayInMs = 1000; + +} // namespace + InkDropAnimationControllerImpl::InkDropAnimationControllerImpl( InkDropHost* ink_drop_host) - : ink_drop_host_(ink_drop_host) {} + : ink_drop_host_(ink_drop_host), + ink_drop_large_corner_radius_(0), + ink_drop_small_corner_radius_(0), + root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), + hover_after_animation_timer_(nullptr) { + root_layer_->set_name("InkDropAnimationControllerImpl:RootLayer"); + ink_drop_host_->AddInkDropLayer(root_layer_.get()); +} InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() { // Explicitly destroy the InkDropAnimation so that this still exists if // views::InkDropAnimationObserver methods are called on this. DestroyInkDropAnimation(); + ink_drop_host_->RemoveInkDropLayer(root_layer_.get()); } InkDropState InkDropAnimationControllerImpl::GetInkDropState() const { @@ -32,6 +67,18 @@ ink_drop_animation_->AnimateToState(ink_drop_state); } +void InkDropAnimationControllerImpl::SetHovered(bool is_hovered) { + SetHoveredInternal(is_hovered, + is_hovered ? base::TimeDelta::FromMilliseconds( + kHoverFadeInFromUserInputDurationInMs) + : base::TimeDelta::FromMilliseconds( + kHoverFadeOutFromUserInputDurationInMs)); +} + +bool InkDropAnimationControllerImpl::IsHovered() const { + return hover_ && hover_->IsVisible(); +} + gfx::Size InkDropAnimationControllerImpl::GetInkDropLargeSize() const { return ink_drop_large_size_; } @@ -49,7 +96,9 @@ ink_drop_large_corner_radius_ = large_corner_radius; ink_drop_small_size_ = small_size; ink_drop_small_corner_radius_ = small_corner_radius; - ink_drop_animation_.reset(); + + DestroyInkDropAnimation(); + DestroyInkDropHover(); } void InkDropAnimationControllerImpl::SetInkDropCenter( @@ -57,6 +106,8 @@ ink_drop_center_ = center_point; if (ink_drop_animation_) ink_drop_animation_->SetCenterPoint(ink_drop_center_); + if (hover_) + hover_->SetCenterPoint(ink_drop_center_); } void InkDropAnimationControllerImpl::CreateInkDropAnimation() { @@ -68,19 +119,40 @@ ink_drop_animation_->AddObserver(this); ink_drop_animation_->SetCenterPoint(ink_drop_center_); - ink_drop_host_->AddInkDropLayer(ink_drop_animation_->root_layer()); + root_layer_->Add(ink_drop_animation_->root_layer()); } void InkDropAnimationControllerImpl::DestroyInkDropAnimation() { if (!ink_drop_animation_) return; - ink_drop_host_->RemoveInkDropLayer(ink_drop_animation_->root_layer()); + root_layer_->Remove(ink_drop_animation_->root_layer()); ink_drop_animation_->RemoveObserver(this); ink_drop_animation_.reset(); } +void InkDropAnimationControllerImpl::CreateInkDropHover() { + DestroyInkDropHover(); + + hover_.reset( + new InkDropHover(ink_drop_small_size_, ink_drop_small_corner_radius_)); + hover_->SetCenterPoint(ink_drop_center_); + root_layer_->Add(hover_->layer()); +} + +void InkDropAnimationControllerImpl::DestroyInkDropHover() { + if (!hover_) + return; + root_layer_->Remove(hover_->layer()); + hover_.reset(); +} + void InkDropAnimationControllerImpl::InkDropAnimationStarted( - InkDropState ink_drop_state) {} + InkDropState ink_drop_state) { + if (IsHovered() && ink_drop_state != views::InkDropState::HIDDEN) { + SetHoveredInternal(false, base::TimeDelta::FromMilliseconds( + kHoverFadeOutBeforeAnimationDurationInMs)); + } +} void InkDropAnimationControllerImpl::InkDropAnimationEnded( InkDropState ink_drop_state, @@ -94,6 +166,9 @@ ink_drop_animation_->AnimateToState(views::InkDropState::HIDDEN); break; case views::InkDropState::HIDDEN: + // TODO(bruthig): Consider only starting the timer if the InkDropHost is + // hovered now, as oppposed to when the timer fires. + StartHoverAfterAnimationTimer(); // TODO(bruthig): Investigate whether creating and destroying // InkDropAnimations is expensive and consider creating an // InkDropAnimationPool. See www.crbug.com/522175. @@ -104,4 +179,48 @@ } } +void InkDropAnimationControllerImpl::SetHoveredInternal( + bool is_hovered, + base::TimeDelta animation_duration) { + StopHoverAfterAnimationTimer(); + + if (IsHovered() == is_hovered) + return; + + if (is_hovered) { + if (!hover_) + CreateInkDropHover(); + if (GetInkDropState() == views::InkDropState::HIDDEN) { + hover_->FadeIn(animation_duration); + } + } else { + hover_->FadeOut(animation_duration); + } +} + +void InkDropAnimationControllerImpl::StartHoverAfterAnimationTimer() { + StopHoverAfterAnimationTimer(); + + if (!hover_after_animation_timer_) + hover_after_animation_timer_.reset(new base::OneShotTimer); + + hover_after_animation_timer_->Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kHoverFadeInAfterAnimationDelayInMs), + base::Bind(&InkDropAnimationControllerImpl::HoverAfterAnimationTimerFired, + base::Unretained(this))); +} + +void InkDropAnimationControllerImpl::StopHoverAfterAnimationTimer() { + if (hover_after_animation_timer_) + hover_after_animation_timer_.reset(); +} + +void InkDropAnimationControllerImpl::HoverAfterAnimationTimerFired() { + SetHoveredInternal(ink_drop_host_->ShouldShowInkDropHover(), + base::TimeDelta::FromMilliseconds( + kHoverFadeInAfterAnimationDurationInMs)); + hover_after_animation_timer_.reset(); +} + } // namespace views
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.h b/ui/views/animation/ink_drop_animation_controller_impl.h index c533883..ff29f9f8 100644 --- a/ui/views/animation/ink_drop_animation_controller_impl.h +++ b/ui/views/animation/ink_drop_animation_controller_impl.h
@@ -13,9 +13,15 @@ #include "ui/views/animation/ink_drop_animation_observer.h" #include "ui/views/views_export.h" +namespace base { +class Timer; +} // namespace base + namespace views { class InkDropAnimation; class InkDropHost; +class InkDropHover; +class InkDropAnimationControllerFactoryTest; // A functional implementation of an InkDropAnimationController. class VIEWS_EXPORT InkDropAnimationControllerImpl @@ -30,6 +36,8 @@ // InkDropAnimationController: InkDropState GetInkDropState() const override; void AnimateToState(InkDropState ink_drop_state) override; + void SetHovered(bool is_hovered) override; + bool IsHovered() const override; gfx::Size GetInkDropLargeSize() const override; void SetInkDropSize(const gfx::Size& large_size, int large_corner_radius, @@ -38,6 +46,9 @@ void SetInkDropCenter(const gfx::Point& center_point) override; private: + friend class InkDropAnimationControllerFactoryTest; + friend class InkDropAnimationControllerImplTest; + // Creates a new InkDropAnimation and sets it to |ink_drop_animation_|. If // |ink_drop_animation_| wasn't null then it will be destroyed using // DestroyInkDropAnimation(). @@ -46,12 +57,35 @@ // Destroys the current |ink_drop_animation_|. void DestroyInkDropAnimation(); + // Creates a new InkDropHover and sets it to |hover_|. If |hover_| wasn't null + // then it will be destroyed using DestroyInkDropHover(). + void CreateInkDropHover(); + + // Destroys the current |hover_|. + void DestroyInkDropHover(); + // views::InkDropAnimationObserver: void InkDropAnimationStarted(InkDropState ink_drop_state) override; void InkDropAnimationEnded(InkDropState ink_drop_state, InkDropAnimationEndedReason reason) override; - // The host of the ink drop. + // Enables or disables the hover state based on |is_hovered| and if an + // animation is triggered it will be scheduled to have the given + // |animation_duration|. + void SetHoveredInternal(bool is_hovered, base::TimeDelta animation_duration); + + // Starts the |hover_after_animation_timer_| timer. This will stop the current + // |hover_after_animation_timer_| instance if it exists. + void StartHoverAfterAnimationTimer(); + + // Stops and destroys the current |hover_after_animation_timer_| instance. + void StopHoverAfterAnimationTimer(); + + // Callback for when the |hover_after_animation_timer_| fires. + void HoverAfterAnimationTimerFired(); + + // The host of the ink drop. Used to poll for information such as whether the + // hover should be shown or not. InkDropHost* ink_drop_host_; // Cached size for the ink drop's large size animations. @@ -69,10 +103,21 @@ // Cached center point for the ink drop. gfx::Point ink_drop_center_; + // The root Layer that parents the InkDropAnimation layers and the + // InkDropHover layers. The |root_layer_| is the one that is added and removed + // from the InkDropHost. + scoped_ptr<ui::Layer> root_layer_; + + // The current InkDropHover. Lazily created using CreateInkDropHover(); + scoped_ptr<InkDropHover> hover_; + // The current InkDropAnimation. Created on demand using // CreateInkDropAnimation(). scoped_ptr<InkDropAnimation> ink_drop_animation_; + // The timer used to delay the hover fade in after an ink drop animation. + scoped_ptr<base::Timer> hover_after_animation_timer_; + DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImpl); };
diff --git a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc new file mode 100644 index 0000000..78fd2b6 --- /dev/null +++ b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
@@ -0,0 +1,87 @@ +// 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 "base/macros.h" +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/views/animation/ink_drop_animation_controller_impl.h" +#include "ui/views/animation/test/test_ink_drop_host.h" + +namespace views { + +// NOTE: The InkDropAnimationControllerImpl class is also tested by the +// InkDropAnimationControllerFactoryTest tests. +class InkDropAnimationControllerImplTest : public testing::Test { + public: + InkDropAnimationControllerImplTest(); + ~InkDropAnimationControllerImplTest() override; + + protected: + TestInkDropHost ink_drop_host_; + + // The test target. + InkDropAnimationControllerImpl ink_drop_animation_controller_; + + // Used to control the tasks scheduled by the InkDropAnimationControllerImpl's + // Timer. + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; + + // Required by base::Timer's. + scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; + + private: + // Ensures all animations complete immediately. + scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + + DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImplTest); +}; + +InkDropAnimationControllerImplTest::InkDropAnimationControllerImplTest() + : ink_drop_animation_controller_(&ink_drop_host_), + task_runner_(new base::TestSimpleTaskRunner), + thread_task_runner_handle_( + new base::ThreadTaskRunnerHandle(task_runner_)) { + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); +} + +InkDropAnimationControllerImplTest::~InkDropAnimationControllerImplTest() {} + +TEST_F(InkDropAnimationControllerImplTest, SetHoveredIsHovered) { + ink_drop_host_.set_should_show_hover(true); + + ink_drop_animation_controller_.SetHovered(true); + EXPECT_TRUE(ink_drop_animation_controller_.IsHovered()); + + ink_drop_animation_controller_.SetHovered(false); + EXPECT_FALSE(ink_drop_animation_controller_.IsHovered()); +} + +TEST_F(InkDropAnimationControllerImplTest, + HoveredStateAfterHoverTimerFiresWhenHostIsHovered) { + ink_drop_host_.set_should_show_hover(true); + ink_drop_animation_controller_.AnimateToState(InkDropState::QUICK_ACTION); + + EXPECT_TRUE(task_runner_->HasPendingTask()); + + task_runner_->RunPendingTasks(); + + EXPECT_TRUE(ink_drop_animation_controller_.IsHovered()); +} + +TEST_F(InkDropAnimationControllerImplTest, + HoveredStateAfterHoverTimerFiresWhenHostIsNotHovered) { + ink_drop_host_.set_should_show_hover(false); + ink_drop_animation_controller_.AnimateToState(InkDropState::QUICK_ACTION); + + EXPECT_TRUE(task_runner_->HasPendingTask()); + + task_runner_->RunPendingTasks(); + + EXPECT_FALSE(ink_drop_animation_controller_.IsHovered()); +} + +} // namespace views
diff --git a/ui/views/animation/ink_drop_delegate.h b/ui/views/animation/ink_drop_delegate.h index 576b742..0bf265a 100644 --- a/ui/views/animation/ink_drop_delegate.h +++ b/ui/views/animation/ink_drop_delegate.h
@@ -42,6 +42,9 @@ // as well as a NONE value. virtual void OnAction(InkDropState state) = 0; + // Enables or disables the hover state. + virtual void SetHovered(bool is_hovered) = 0; + private: DISALLOW_COPY_AND_ASSIGN(InkDropDelegate); };
diff --git a/ui/views/animation/ink_drop_host.h b/ui/views/animation/ink_drop_host.h index f50fac78..ab9f165 100644 --- a/ui/views/animation/ink_drop_host.h +++ b/ui/views/animation/ink_drop_host.h
@@ -34,9 +34,11 @@ virtual void RemoveInkDropLayer(ui::Layer* ink_drop_layer) = 0; // Returns the Point where the ink drop should be centered. - // TODO(varkha): This should be moved to InkDropConsumer. virtual gfx::Point CalculateInkDropCenter() const = 0; + // Returns true if the InkDropHover should be shown. + virtual bool ShouldShowInkDropHover() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(InkDropHost); };
diff --git a/ui/views/animation/ink_drop_hover.cc b/ui/views/animation/ink_drop_hover.cc new file mode 100644 index 0000000..8f17674 --- /dev/null +++ b/ui/views/animation/ink_drop_hover.cc
@@ -0,0 +1,102 @@ +// 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/animation/ink_drop_hover.h" + +#include "third_party/skia/include/core/SkColor.h" +#include "ui/compositor/callback_layer_animation_observer.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_sequence.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/views/animation/ink_drop_painted_layer_delegates.h" + +namespace views { + +namespace { + +// The opacity of the hover when it is visible. +const float kHoverVisibleOpacity = 0.08f; + +// The opacity of the hover when it is not visible. +const float kHiddenOpacity = 0.0f; + +// The hover color. +const SkColor kHoverColor = SK_ColorBLACK; + +} // namespace + +InkDropHover::InkDropHover(const gfx::Size& size, int corner_radius) + : layer_delegate_( + new RoundedRectangleLayerDelegate(kHoverColor, size, corner_radius)), + layer_(new ui::Layer()) { + layer_->SetBounds(gfx::Rect(size)); + layer_->SetFillsBoundsOpaquely(false); + layer_->set_delegate(layer_delegate_.get()); + layer_->SetVisible(false); + layer_->SetOpacity(kHoverVisibleOpacity); + layer_->SetMasksToBounds(false); + layer_->set_name("InkDropHover:layer"); + SetCenterPoint(gfx::Rect(size).CenterPoint()); +} + +InkDropHover::~InkDropHover() {} + +bool InkDropHover::IsVisible() const { + return layer_->visible(); +} + +void InkDropHover::FadeIn(const base::TimeDelta& duration) { + layer_->SetOpacity(kHiddenOpacity); + layer_->SetVisible(true); + AnimateFade(FADE_IN, duration); +} + +void InkDropHover::FadeOut(const base::TimeDelta& duration) { + AnimateFade(FADE_OUT, duration); +} + +void InkDropHover::AnimateFade(HoverAnimationType animation_type, + const base::TimeDelta& duration) { + // The |animation_observer| will be destroyed when the + // AnimationStartedCallback() returns true. + ui::CallbackLayerAnimationObserver* animation_observer = + new ui::CallbackLayerAnimationObserver( + base::Bind(&InkDropHover::AnimationEndedCallback, + base::Unretained(this), animation_type)); + + ui::LayerAnimator* animator = layer_->GetAnimator(); + ui::ScopedLayerAnimationSettings animation(animator); + animation.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + ui::LayerAnimationElement* animation_element = + ui::LayerAnimationElement::CreateOpacityElement( + animation_type == FADE_IN ? kHoverVisibleOpacity : kHiddenOpacity, + duration); + ui::LayerAnimationSequence* animation_sequence = + new ui::LayerAnimationSequence(animation_element); + animation_sequence->AddObserver(animation_observer); + + animator->StartAnimation(animation_sequence); + + animation_observer->SetActive(); +} + +void InkDropHover::SetCenterPoint(const gfx::Point& center_point) { + gfx::Transform transform; + transform.Translate(center_point.x() - layer_->bounds().CenterPoint().x(), + center_point.y() - layer_->bounds().CenterPoint().y()); + layer_->SetTransform(transform); +} + +bool InkDropHover::AnimationEndedCallback( + HoverAnimationType animation_type, + const ui::CallbackLayerAnimationObserver& observer) { + // AnimationEndedCallback() may be invoked when this is being destroyed and + // |layer_| may be null. + if (animation_type == FADE_OUT && layer_) + layer_->SetVisible(false); + return true; +} + +} // namespace views
diff --git a/ui/views/animation/ink_drop_hover.h b/ui/views/animation/ink_drop_hover.h new file mode 100644 index 0000000..462bbbe --- /dev/null +++ b/ui/views/animation/ink_drop_hover.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 UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/views_export.h" + +namespace ui { +class Layer; +class CallbackLayerAnimationObserver; +} // namespace ui + +namespace views { +class RoundedRectangleLayerDelegate; + +// Manages fade in/out animations for a painted Layer that is used to provide +// visual feedback on ui::Views for mouse hover states. +class VIEWS_EXPORT InkDropHover { + public: + InkDropHover(const gfx::Size& size, int corner_radius); + ~InkDropHover(); + + // Returns true if the hover layer is visible. + bool IsVisible() const; + + // Fades in the hover visual over the given |duration|. + void FadeIn(const base::TimeDelta& duration); + + // Fades out the hover visual over the given |duration|. + void FadeOut(const base::TimeDelta& duration); + + // The root Layer that can be added in to a Layer tree. + ui::Layer* layer() { return layer_.get(); } + + // Sets the |center_point| of the hover layer relative to its parent Layer. + void SetCenterPoint(const gfx::Point& center_point); + + private: + enum HoverAnimationType { FADE_IN, FADE_OUT }; + + // Animates a fade in/out as specified by |animation_type| over the given + // |duration|. + void AnimateFade(HoverAnimationType animation_type, + const base::TimeDelta& duration); + + // The callback that will be invoked when a fade in/out animation is complete. + bool AnimationEndedCallback( + HoverAnimationType animation_type, + const ui::CallbackLayerAnimationObserver& observer); + + // The LayerDelegate that paints the hover |layer_|. + scoped_ptr<RoundedRectangleLayerDelegate> layer_delegate_; + + // The visual hover layer that is painted by |layer_delegate_|. + scoped_ptr<ui::Layer> layer_; + + DISALLOW_COPY_AND_ASSIGN(InkDropHover); +}; + +} // namespace views + +#endif // UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_
diff --git a/ui/views/animation/ink_drop_hover_unittest.cc b/ui/views/animation/ink_drop_hover_unittest.cc new file mode 100644 index 0000000..08ee8b9 --- /dev/null +++ b/ui/views/animation/ink_drop_hover_unittest.cc
@@ -0,0 +1,58 @@ +// 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/animation/ink_drop_hover.h" + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/gfx/geometry/size.h" + +namespace views { +namespace test { + +class InkDropHoverTest : public testing::Test { + public: + InkDropHoverTest(); + ~InkDropHoverTest() override; + + protected: + scoped_ptr<InkDropHover> CreateInkDropHover() const; + + private: + // Enables zero duration animations during the tests. + scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + + DISALLOW_COPY_AND_ASSIGN(InkDropHoverTest); +}; + +InkDropHoverTest::InkDropHoverTest() { + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); +} + +InkDropHoverTest::~InkDropHoverTest() {} + +scoped_ptr<InkDropHover> InkDropHoverTest::CreateInkDropHover() const { + return make_scoped_ptr(new InkDropHover(gfx::Size(10, 10), 3)); +} + +TEST_F(InkDropHoverTest, InitialStateAfterConstruction) { + scoped_ptr<InkDropHover> ink_drop_hover = CreateInkDropHover(); + EXPECT_FALSE(ink_drop_hover->IsVisible()); +} + +TEST_F(InkDropHoverTest, IsHoveredStateTransitions) { + scoped_ptr<InkDropHover> ink_drop_hover = CreateInkDropHover(); + + ink_drop_hover->FadeIn(base::TimeDelta::FromMilliseconds(0)); + EXPECT_TRUE(ink_drop_hover->IsVisible()); + + ink_drop_hover->FadeOut(base::TimeDelta::FromMilliseconds(0)); + EXPECT_FALSE(ink_drop_hover->IsVisible()); +} + +} // namespace test +} // namespace views
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.cc b/ui/views/animation/ink_drop_painted_layer_delegates.cc index bdb7946..7d43b8a 100644 --- a/ui/views/animation/ink_drop_painted_layer_delegates.cc +++ b/ui/views/animation/ink_drop_painted_layer_delegates.cc
@@ -8,6 +8,7 @@ #include "ui/compositor/paint_recorder.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/geometry/rect_f.h" namespace views { @@ -82,4 +83,34 @@ canvas->DrawRect(gfx::Rect(size_), paint); } +//////////////////////////////////////////////////////////////////////////////// +// +// RoundedRectangleLayerDelegate +// + +RoundedRectangleLayerDelegate::RoundedRectangleLayerDelegate(SkColor color, + gfx::Size size, + int corner_radius) + : BasePaintedLayerDelegate(color), + size_(size), + corner_radius_(corner_radius) {} + +RoundedRectangleLayerDelegate::~RoundedRectangleLayerDelegate() {} + +gfx::PointF RoundedRectangleLayerDelegate::GetCenterPoint() const { + return gfx::RectF(gfx::SizeF(size_)).CenterPoint(); +} + +void RoundedRectangleLayerDelegate::OnPaintLayer( + const ui::PaintContext& context) { + SkPaint paint; + paint.setColor(color()); + paint.setFlags(SkPaint::kAntiAlias_Flag); + paint.setStyle(SkPaint::kFill_Style); + + ui::PaintRecorder recorder(context, size_); + gfx::Canvas* canvas = recorder.canvas(); + canvas->DrawRoundRect(gfx::Rect(size_), corner_radius_, paint); +} + } // namespace views
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.h b/ui/views/animation/ink_drop_painted_layer_delegates.h index feb2921..57d6f17da 100644 --- a/ui/views/animation/ink_drop_painted_layer_delegates.h +++ b/ui/views/animation/ink_drop_painted_layer_delegates.h
@@ -81,6 +81,31 @@ DISALLOW_COPY_AND_ASSIGN(RectangleLayerDelegate); }; +// A BasePaintedLayerDelegate that paints a rounded rectangle of a specified +// color, size and corner radius. +class RoundedRectangleLayerDelegate : public BasePaintedLayerDelegate { + public: + RoundedRectangleLayerDelegate(SkColor color, + gfx::Size size, + int corner_radius); + ~RoundedRectangleLayerDelegate() override; + + const gfx::Size& size() const { return size_; } + + // ui::LayerDelegate: + gfx::PointF GetCenterPoint() const override; + void OnPaintLayer(const ui::PaintContext& context) override; + + private: + // The size of the rectangle. + gfx::Size size_; + + // The radius of the corners. + int corner_radius_; + + DISALLOW_COPY_AND_ASSIGN(RoundedRectangleLayerDelegate); +}; + } // namespace views #endif // UI_VIEWS_ANIMATION_INK_DROP_PAINTED_LAYER_DELEGATES_H_
diff --git a/ui/views/animation/test/test_ink_drop_host.cc b/ui/views/animation/test/test_ink_drop_host.cc index 689f997..3b46616 100644 --- a/ui/views/animation/test/test_ink_drop_host.cc +++ b/ui/views/animation/test/test_ink_drop_host.cc
@@ -6,7 +6,8 @@ namespace views { -TestInkDropHost::TestInkDropHost() : num_ink_drop_layers_(0) {} +TestInkDropHost::TestInkDropHost() + : num_ink_drop_layers_(0), should_show_hover_(false) {} TestInkDropHost::~TestInkDropHost() {} @@ -22,4 +23,8 @@ return gfx::Point(); } +bool TestInkDropHost::ShouldShowInkDropHover() const { + return should_show_hover_; +} + } // namespace views
diff --git a/ui/views/animation/test/test_ink_drop_host.h b/ui/views/animation/test/test_ink_drop_host.h index 7baa391..9192a116 100644 --- a/ui/views/animation/test/test_ink_drop_host.h +++ b/ui/views/animation/test/test_ink_drop_host.h
@@ -19,14 +19,21 @@ int num_ink_drop_layers() const { return num_ink_drop_layers_; } + void set_should_show_hover(bool should_show_hover) { + should_show_hover_ = should_show_hover; + } + // TestInkDropHost: void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; gfx::Point CalculateInkDropCenter() const override; + bool ShouldShowInkDropHover() const override; private: int num_ink_drop_layers_; + bool should_show_hover_; + DISALLOW_COPY_AND_ASSIGN(TestInkDropHost); };
diff --git a/ui/views/button_drag_utils.cc b/ui/views/button_drag_utils.cc index 3fb5d12..60bd6e5a 100644 --- a/ui/views/button_drag_utils.cc +++ b/ui/views/button_drag_utils.cc
@@ -14,7 +14,10 @@ #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/image/image.h" #include "ui/resources/grit/ui_resources.h" +#include "ui/views/background.h" +#include "ui/views/border.h" #include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/label_button_border.h" #include "ui/views/drag_utils.h" #include "ui/views/resources/grit/views_resources.h" #include "ui/views/widget/widget.h" @@ -49,13 +52,17 @@ button.SetTextSubpixelRenderingEnabled(false); const ui::NativeTheme* theme = widget->GetNativeTheme(); button.SetTextColor(views::Button::STATE_NORMAL, - theme->GetSystemColor(ui::NativeTheme::kColorId_LabelEnabledColor)); - gfx::ShadowValues shadows( - 10, - gfx::ShadowValue(gfx::Vector2d(0, 0), 1.0f, - theme->GetSystemColor( - ui::NativeTheme::kColorId_LabelBackgroundColor))); - button.SetTextShadows(shadows); + theme->GetSystemColor(ui::NativeTheme::kColorId_TextfieldDefaultColor)); + + SkColor bg_color = theme->GetSystemColor( + ui::NativeTheme::kColorId_TextfieldDefaultBackground); + if (widget->IsTranslucentWindowOpacitySupported()) { + button.SetTextShadows(gfx::ShadowValues( + 10, gfx::ShadowValue(gfx::Vector2d(0, 0), 1.0f, bg_color))); + } else { + button.set_background(views::Background::CreateSolidBackground(bg_color)); + button.SetBorder(button.CreateDefaultBorder()); + } button.SetMaxSize(gfx::Size(kLinkDragImageMaxWidth, 0)); if (icon.isNull()) { button.SetImage(views::Button::STATE_NORMAL,
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc index 3ab8303..3dfc48d6 100644 --- a/ui/views/controls/button/custom_button.cc +++ b/ui/views/controls/button/custom_button.cc
@@ -123,6 +123,8 @@ } void CustomButton::OnEnabledChanged() { + // TODO(bruthig): Is there any reason we are not calling + // Button::OnEnabledChanged() here? if (enabled() ? (state_ != STATE_DISABLED) : (state_ == STATE_DISABLED)) return; @@ -130,6 +132,7 @@ SetState(ShouldEnterHoveredState() ? STATE_HOVERED : STATE_NORMAL); else SetState(STATE_DISABLED); + UpdateInkDropHoverState(); } const char* CustomButton::GetClassName() const { @@ -352,6 +355,10 @@ return GetLocalBounds().CenterPoint(); } +bool CustomButton::ShouldShowInkDropHover() const { + return enabled() && IsMouseHovered() && !InDrag(); +} + //////////////////////////////////////////////////////////////////////////////// // CustomButton, protected: @@ -408,6 +415,11 @@ return check_mouse_position && IsMouseHovered(); } +void CustomButton::UpdateInkDropHoverState() { + if (ink_drop_delegate_) + ink_drop_delegate_->SetHovered(ShouldShowInkDropHover()); +} + //////////////////////////////////////////////////////////////////////////////// // CustomButton, View overrides (protected):
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h index 6d23e8e..7f39408 100644 --- a/ui/views/controls/button/custom_button.h +++ b/ui/views/controls/button/custom_button.h
@@ -106,6 +106,7 @@ void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; gfx::Point CalculateInkDropCenter() const override; + bool ShouldShowInkDropHover() const override; protected: // Construct the Button with a Listener. See comment for Button's ctor. @@ -136,6 +137,9 @@ // state). This does not take into account enabled state. bool ShouldEnterHoveredState(); + // Updates the |ink_drop_delegate_|'s hover state. + void UpdateInkDropHoverState(); + InkDropDelegate* ink_drop_delegate() const { return ink_drop_delegate_; } void set_ink_drop_delegate(InkDropDelegate* ink_drop_delegate) { ink_drop_delegate_ = ink_drop_delegate;
diff --git a/ui/views/controls/button/custom_button_unittest.cc b/ui/views/controls/button/custom_button_unittest.cc index 7f784c2..41de3466 100644 --- a/ui/views/controls/button/custom_button_unittest.cc +++ b/ui/views/controls/button/custom_button_unittest.cc
@@ -123,6 +123,8 @@ } } + void SetHovered(bool is_hovered) override {} + private: InkDropHost* ink_drop_host_; bool* ink_shown_;
diff --git a/ui/views/drag_utils.cc b/ui/views/drag_utils.cc index 2597bf29..5c64f482 100644 --- a/ui/views/drag_utils.cc +++ b/ui/views/drag_utils.cc
@@ -14,9 +14,6 @@ float GetDeviceScaleForNativeView(views::Widget* widget) { float device_scale = 1.0f; - // The following code should work on other platforms as well. But we do not - // yet care about device scale factor on other platforms. So to keep drag and - // drop behavior on other platforms un-touched, we wrap this in the #if guard. if (widget && widget->GetNativeView()) { gfx::NativeView view = widget->GetNativeView(); gfx::Display display = gfx::Screen::GetScreenFor(view)->
diff --git a/ui/views/mus/platform_window_mus.cc b/ui/views/mus/platform_window_mus.cc index 407d8201..7233c4c 100644 --- a/ui/views/mus/platform_window_mus.cc +++ b/ui/views/mus/platform_window_mus.cc
@@ -5,10 +5,12 @@ #include "ui/views/mus/platform_window_mus.h" #include "build/build_config.h" +#include "components/bitmap_uploader/bitmap_uploader.h" #include "components/mus/public/cpp/property_type_converters.h" #include "components/mus/public/cpp/window_property.h" #include "components/mus/public/interfaces/window_manager.mojom.h" #include "mojo/converters/input_events/input_events_type_converters.h" +#include "ui/base/view_prop.h" #include "ui/platform_window/platform_window_delegate.h" #include "ui/views/mus/window_manager_connection.h" @@ -20,6 +22,7 @@ } // namespace PlatformWindowMus::PlatformWindowMus(ui::PlatformWindowDelegate* delegate, + mojo::Shell* shell, mus::Window* mus_window) : delegate_(delegate), mus_window_(mus_window), @@ -36,14 +39,20 @@ // window and fit in the smallest sizeof(AcceleratedWidget) uint32_t // has this property. #if defined(OS_WIN) || defined(OS_ANDROID) - delegate_->OnAcceleratedWidgetAvailable( - reinterpret_cast<gfx::AcceleratedWidget>(accelerated_widget_count++), - mus_window_->viewport_metrics().device_pixel_ratio); + gfx::AcceleratedWidget accelerated_widget = + reinterpret_cast<gfx::AcceleratedWidget>(accelerated_widget_count++); #else - delegate_->OnAcceleratedWidgetAvailable( - static_cast<gfx::AcceleratedWidget>(accelerated_widget_count++), - mus_window_->viewport_metrics().device_pixel_ratio); + gfx::AcceleratedWidget accelerated_widget = + static_cast<gfx::AcceleratedWidget>(accelerated_widget_count++); #endif + delegate_->OnAcceleratedWidgetAvailable( + accelerated_widget, mus_window_->viewport_metrics().device_pixel_ratio); + + bitmap_uploader_.reset(new bitmap_uploader::BitmapUploader(mus_window_)); + bitmap_uploader_->Init(shell); + prop_.reset(new ui::ViewProp( + accelerated_widget, bitmap_uploader::kBitmapUploaderForAcceleratedWidget, + bitmap_uploader_.get())); } PlatformWindowMus::~PlatformWindowMus() {
diff --git a/ui/views/mus/platform_window_mus.h b/ui/views/mus/platform_window_mus.h index fadd64f..ee124f5 100644 --- a/ui/views/mus/platform_window_mus.h +++ b/ui/views/mus/platform_window_mus.h
@@ -16,6 +16,18 @@ #include "ui/platform_window/platform_window.h" #include "ui/views/mus/mus_export.h" +namespace bitmap_uploader { +class BitmapUploader; +} + +namespace mojo { +class Shell; +} + +namespace ui { +class ViewProp; +} + namespace views { class VIEWS_MUS_EXPORT PlatformWindowMus @@ -24,6 +36,7 @@ public NON_EXPORTED_BASE(mus::InputEventHandler) { public: PlatformWindowMus(ui::PlatformWindowDelegate* delegate, + mojo::Shell* shell, mus::Window* mus_window); ~PlatformWindowMus() override; @@ -82,6 +95,8 @@ // True if OnWindowDestroyed() has been received. bool mus_window_destroyed_; + scoped_ptr<bitmap_uploader::BitmapUploader> bitmap_uploader_; + scoped_ptr<ui::ViewProp> prop_; #ifndef NDEBUG scoped_ptr<base::WeakPtrFactory<PlatformWindowMus>> weak_factory_; #endif
diff --git a/ui/views/mus/window_tree_host_mus.cc b/ui/views/mus/window_tree_host_mus.cc index 6edb53d..ec1ab6ed 100644 --- a/ui/views/mus/window_tree_host_mus.cc +++ b/ui/views/mus/window_tree_host_mus.cc
@@ -4,11 +4,8 @@ #include "ui/views/mus/window_tree_host_mus.h" -#include "components/bitmap_uploader/bitmap_uploader.h" -#include "mojo/shell/public/interfaces/shell.mojom.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" -#include "ui/base/view_prop.h" #include "ui/events/event.h" #include "ui/views/mus/input_method_mus.h" #include "ui/views/mus/native_widget_mus.h" @@ -25,7 +22,8 @@ mus::mojom::SurfaceType surface_type) : native_widget_(native_widget), show_state_(ui::PLATFORM_WINDOW_STATE_UNKNOWN) { - SetPlatformWindow(make_scoped_ptr(new PlatformWindowMus(this, window))); + SetPlatformWindow( + make_scoped_ptr(new PlatformWindowMus(this, shell, window))); // The location of events is already transformed, and there is no way to // correctly determine the reverse transform. So, don't attempt to transform // event locations, else the root location is wrong. @@ -33,13 +31,6 @@ dispatcher()->set_transform_events(false); compositor()->SetHostHasTransparentBackground(true); - bitmap_uploader_.reset(new bitmap_uploader::BitmapUploader(window)); - bitmap_uploader_->Init(shell); - prop_.reset( - new ui::ViewProp(GetAcceleratedWidget(), - bitmap_uploader::kBitmapUploaderForAcceleratedWidget, - bitmap_uploader_.get())); - input_method_.reset(new InputMethodMUS(this, window)); SetSharedInputMethod(input_method_.get()); }
diff --git a/ui/views/mus/window_tree_host_mus.h b/ui/views/mus/window_tree_host_mus.h index 0116e60..f2a58b6 100644 --- a/ui/views/mus/window_tree_host_mus.h +++ b/ui/views/mus/window_tree_host_mus.h
@@ -12,10 +12,6 @@ class SkBitmap; -namespace bitmap_uploader { -class BitmapUploader; -} - namespace mojo { class Shell; } @@ -24,11 +20,6 @@ class Window; } -namespace ui { -class Compositor; -class ViewProp; -} - namespace views { class InputMethodMUS; @@ -44,9 +35,6 @@ ~WindowTreeHostMus() override; PlatformWindowMus* platform_window(); - bitmap_uploader::BitmapUploader* bitmap_uploader() { - return bitmap_uploader_.get(); - } ui::PlatformWindowState show_state() const { return show_state_; } private: @@ -60,8 +48,6 @@ NativeWidgetMus* native_widget_; scoped_ptr<InputMethodMUS> input_method_; ui::PlatformWindowState show_state_; - scoped_ptr<bitmap_uploader::BitmapUploader> bitmap_uploader_; - scoped_ptr<ui::ViewProp> prop_; DISALLOW_COPY_AND_ASSIGN(WindowTreeHostMus); };
diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 15305052..3cf367b 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp
@@ -27,6 +27,8 @@ 'animation/ink_drop_animation_observer.h', 'animation/ink_drop_delegate.h', 'animation/ink_drop_host.h', + 'animation/ink_drop_hover.cc', + 'animation/ink_drop_hover.h', 'animation/ink_drop_painted_layer_delegates.cc', 'animation/ink_drop_painted_layer_delegates.h', 'animation/ink_drop_state.cc', @@ -544,7 +546,9 @@ 'accessible_pane_view_unittest.cc', 'animation/bounds_animator_unittest.cc', 'animation/ink_drop_animation_controller_factory_unittest.cc', + 'animation/ink_drop_animation_controller_impl_unittest.cc', 'animation/ink_drop_animation_unittest.cc', + 'animation/ink_drop_hover_unittest.cc', 'bubble/bubble_border_unittest.cc', 'bubble/bubble_delegate_unittest.cc', 'bubble/bubble_frame_view_unittest.cc',
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 80aaddee..54c6d29 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -209,13 +209,12 @@ WidgetDelegate* delegate; bool child; // If TRANSLUCENT_WINDOW, the widget may be fully or partially transparent. - // Translucent windows may not always be supported. Use - // IsTranslucentWindowOpacitySupported to determine if translucent windows - // are supported. // If OPAQUE_WINDOW, we can perform optimizations based on the widget being - // fully opaque. Defaults to TRANSLUCENT_WINDOW if - // ViewsDelegate::UseTransparentWindows(). Defaults to OPAQUE_WINDOW for - // non-window widgets. + // fully opaque. + // Default is based on ViewsDelegate::GetOpacityForInitParams(). Defaults + // to OPAQUE_WINDOW for non-window widgets. + // Translucent windows may not always be supported. Use + // IsTranslucentWindowOpacitySupported to determine whether they are. WindowOpacity opacity; bool accept_events; Activatable activatable;
diff --git a/ui/webui/resources/css/text_defaults.css b/ui/webui/resources/css/text_defaults.css index 037ade7..4558782 100644 --- a/ui/webui/resources/css/text_defaults.css +++ b/ui/webui/resources/css/text_defaults.css
@@ -16,14 +16,14 @@ * Otherwise its $placeholders won't be expanded. */ html { - direction: ${textDirection}; + direction: $i18n{textDirection}; } body { - font-family: ${fontFamily}; - font-size: ${fontSize}; + font-family: $i18n{fontFamily}; + font-size: $i18n{fontSize}; } button { - font-family: ${fontFamily}; + font-family: $i18n{fontFamily}; }