Update from https://crrev.com/307330 Includes several sky updates for skia API changes and the gn format presubmit check from https://codereview.chromium.org/779193003/ Review URL: https://codereview.chromium.org/786123002
diff --git a/DEPS b/DEPS index aac348f..3ff8a41 100644 --- a/DEPS +++ b/DEPS
@@ -22,19 +22,19 @@ 'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d', 'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '32fee2907e2109ef420c3fec5f44e655ebc55c2a', + 'skia_revision': 'cf56009d9058d25933d9840bf6cf9fdf6a80f647', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and V8 without interference from each other. - 'v8_revision': '5e7bfaf5530837b94fa0c05189c0ab601e3a6355', + 'v8_revision': '4f77f25857dd9ca5b51749006d6183c3eeb2d49b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - "angle_revision": "746d0ea79208b514e95e626310bec513fa666ca4", + "angle_revision": "16545669136028420f67ac496c45c2e9a32ed5a9", # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': 'af2cab762e6de03ee53ba430a596ad98d5006778', + 'buildtools_revision': '535aff24c308a715751028173e569596bcfe12a7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -78,7 +78,7 @@ Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'), 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + '866ff696e9022a6000afbab516fba62cfa306075', # from svn revision 293126 + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '53ecf0f68b27a004bef5526553b8e5f6c235b80b', 'src/third_party/libc++/trunk': Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + Var('libcxx_revision'), @@ -87,7 +87,7 @@ Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' + Var('libcxxabi_revision'), 'src/tools/grit': - Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a24a0e647bb718b3540db89864cf586b12331e82', # from svn revision 182 + Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'ba706f5aa055960b40927d7e5b42186acac9c5e6', # from svn revision 184 'src/v8': Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'),
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 47ccdc7..ce66452 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -1542,6 +1542,8 @@ results.extend(_CommonChecks(input_api, output_api)) results.extend(_CheckValidHostsInDEPS(input_api, output_api)) results.extend(_CheckJavaStyle(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckGNFormatted(input_api, output_api)) return results
diff --git a/base/command_line.cc b/base/command_line.cc index 1f5edce..fb7c813 100644 --- a/base/command_line.cc +++ b/base/command_line.cc
@@ -70,7 +70,7 @@ } // Append switches and arguments, keeping switches before arguments. -void AppendSwitchesAndArguments(CommandLine& command_line, +void AppendSwitchesAndArguments(CommandLine* command_line, const CommandLine::StringVector& argv) { bool parse_switches = true; for (size_t i = 1; i < argv.size(); ++i) { @@ -82,13 +82,13 @@ parse_switches &= (arg != kSwitchTerminator); if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { #if defined(OS_WIN) - command_line.AppendSwitchNative(UTF16ToASCII(switch_string), - switch_value); + command_line->AppendSwitchNative(UTF16ToASCII(switch_string), + switch_value); #elif defined(OS_POSIX) - command_line.AppendSwitchNative(switch_string, switch_value); + command_line->AppendSwitchNative(switch_string, switch_value); #endif } else { - command_line.AppendArgNative(arg); + command_line->AppendArgNative(arg); } } } @@ -96,7 +96,7 @@ // Lowercase switches for backwards compatiblity *on Windows*. std::string LowerASCIIOnWindows(const std::string& string) { #if defined(OS_WIN) - return base::StringToLowerASCII(string); + return StringToLowerASCII(string); #elif defined(OS_POSIX) return string; #endif @@ -105,28 +105,27 @@ #if defined(OS_WIN) // Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. -base::string16 QuoteForCommandLineToArgvW(const base::string16& arg, - bool quote_placeholders) { +string16 QuoteForCommandLineToArgvW(const string16& arg, + bool quote_placeholders) { // We follow the quoting rules of CommandLineToArgvW. // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - base::string16 quotable_chars(L" \\\""); + string16 quotable_chars(L" \\\""); // We may also be required to quote '%', which is commonly used in a command // line as a placeholder. (It may be substituted for a string with spaces.) if (quote_placeholders) quotable_chars.push_back(L'%'); - if (arg.find_first_of(quotable_chars) == base::string16::npos) { + if (arg.find_first_of(quotable_chars) == string16::npos) { // No quoting necessary. return arg; } - base::string16 out; + string16 out; out.push_back(L'"'); for (size_t i = 0; i < arg.size(); ++i) { if (arg[i] == '\\') { // Find the extent of this run of backslashes. size_t start = i, end = start + 1; - for (; end < arg.size() && arg[end] == '\\'; ++end) - /* empty */; + for (; end < arg.size() && arg[end] == '\\'; ++end) {} size_t backslash_count = end - start; // Backslashes are escapes only if the run is followed by a double quote. @@ -230,7 +229,7 @@ #if defined(OS_WIN) // static -CommandLine CommandLine::FromString(const base::string16& command_line) { +CommandLine CommandLine::FromString(const string16& command_line) { CommandLine cmd(NO_PROGRAM); cmd.ParseFromString(command_line); return cmd; @@ -250,7 +249,7 @@ switches_.clear(); begin_args_ = 1; SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); - AppendSwitchesAndArguments(*this, argv); + AppendSwitchesAndArguments(this, argv); } FilePath CommandLine::GetProgram() const { @@ -304,7 +303,7 @@ const CommandLine::StringType& value) { std::string switch_key(LowerASCIIOnWindows(switch_string)); #if defined(OS_WIN) - StringType combined_switch_string(ASCIIToWide(switch_key)); + StringType combined_switch_string(ASCIIToUTF16(switch_key)); #elif defined(OS_POSIX) StringType combined_switch_string(switch_string); #endif @@ -322,7 +321,7 @@ void CommandLine::AppendSwitchASCII(const std::string& switch_string, const std::string& value_string) { #if defined(OS_WIN) - AppendSwitchNative(switch_string, ASCIIToWide(value_string)); + AppendSwitchNative(switch_string, ASCIIToUTF16(value_string)); #elif defined(OS_POSIX) AppendSwitchNative(switch_string, value_string); #endif @@ -369,7 +368,7 @@ bool include_program) { if (include_program) SetProgram(other.GetProgram()); - AppendSwitchesAndArguments(*this, other.argv()); + AppendSwitchesAndArguments(this, other.argv()); } void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { @@ -385,8 +384,8 @@ } #if defined(OS_WIN) -void CommandLine::ParseFromString(const base::string16& command_line) { - base::string16 command_line_string; +void CommandLine::ParseFromString(const string16& command_line) { + string16 command_line_string; TrimWhitespace(command_line, TRIM_ALL, &command_line_string); if (command_line_string.empty()) return; @@ -437,8 +436,7 @@ #endif params.append(kSwitchValueSeparator + switch_value); } - } - else { + } else { #if defined(OS_WIN) arg = QuoteForCommandLineToArgvW(arg, quote_placeholders); #endif
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc index c9f2267..cbc0dd0 100644 --- a/base/debug/proc_maps_linux_unittest.cc +++ b/base/debug/proc_maps_linux_unittest.cc
@@ -181,20 +181,19 @@ } } -TEST(ProcMapsTest, ReadProcMaps) { - std::string proc_maps; - ASSERT_TRUE(ReadProcMaps(&proc_maps)); - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); - ASSERT_FALSE(regions.empty()); - +#if defined(ADDRESS_SANITIZER) +// AddressSanitizer may move local variables to a dedicated "fake stack" which +// is outside the stack region listed in /proc/self/maps. We disable ASan +// instrumentation for this function to force the variable to be local. +__attribute__((no_sanitize_address)) +#endif +void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> ®ions) { // We should be able to find both the current executable as well as the stack - // mapped into memory. Use the address of |proc_maps| as a way of finding the + // mapped into memory. Use the address of |exe_path| as a way of finding the // stack. FilePath exe_path; EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); - uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps); + uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path); bool found_exe = false; bool found_stack = false; bool found_address = false; @@ -246,6 +245,17 @@ } } +TEST(ProcMapsTest, ReadProcMaps) { + std::string proc_maps; + ASSERT_TRUE(ReadProcMaps(&proc_maps)); + + std::vector<MappedMemoryRegion> regions; + ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); + ASSERT_FALSE(regions.empty()); + + CheckProcMapsRegions(regions); +} + TEST(ProcMapsTest, ReadProcMapsNonEmptyString) { std::string old_string("I forgot to clear the string"); std::string proc_maps(old_string);
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc index b511d3c..e254232 100644 --- a/base/files/file_util_win.cc +++ b/base/files/file_util_win.cc
@@ -480,7 +480,7 @@ } // Move to the next drive letter string, which starts one // increment after the '\0' that terminates the current string. - while (*drive_map_ptr++); + while (*drive_map_ptr++) {} } // No drive matched. The path does not start with a device junction @@ -496,7 +496,7 @@ // code below to a call to GetFinalPathNameByHandle(). The method this // function uses is explained in the following msdn article: // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx - base::win::ScopedHandle file_handle( + win::ScopedHandle file_handle( ::CreateFile(path.value().c_str(), GENERIC_READ, kFileShareAll, @@ -510,7 +510,7 @@ // Create a file mapping object. Can't easily use MemoryMappedFile, because // we only map the first byte, and need direct access to the handle. You can // not map an empty file, this call fails in that case. - base::win::ScopedHandle file_map_handle( + win::ScopedHandle file_map_handle( ::CreateFileMapping(file_handle.Get(), NULL, PAGE_READONLY, @@ -575,7 +575,7 @@ FILE* OpenFile(const FilePath& filename, const char* mode) { ThreadRestrictions::AssertIOAllowed(); - std::wstring w_mode = ASCIIToWide(std::string(mode)); + string16 w_mode = ASCIIToUTF16(mode); return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); } @@ -595,13 +595,13 @@ int ReadFile(const FilePath& filename, char* data, int max_size) { ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL)); + win::ScopedHandle file(CreateFile(filename.value().c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL)); if (!file.IsValid()) return -1; @@ -614,13 +614,13 @@ int WriteFile(const FilePath& filename, const char* data, int size) { ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - 0, - NULL)); + win::ScopedHandle file(CreateFile(filename.value().c_str(), + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + 0, + NULL)); if (!file.IsValid()) { DPLOG(WARNING) << "CreateFile failed for path " << UTF16ToUTF8(filename.value()); @@ -646,13 +646,13 @@ bool AppendToFile(const FilePath& filename, const char* data, int size) { ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - FILE_APPEND_DATA, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL)); + win::ScopedHandle file(CreateFile(filename.value().c_str(), + FILE_APPEND_DATA, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL)); if (!file.IsValid()) { VPLOG(1) << "CreateFile failed for path " << UTF16ToUTF8(filename.value()); return false;
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h index fca9a50..d9d7e19 100644 --- a/base/ios/ios_util.h +++ b/base/ios/ios_util.h
@@ -11,9 +11,6 @@ namespace base { namespace ios { -// Returns whether the operating system is iOS 7 or later. -BASE_EXPORT bool IsRunningOnIOS7OrLater(); - // Returns whether the operating system is iOS 8 or later. BASE_EXPORT bool IsRunningOnIOS8OrLater();
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm index 91fce0c..ca0a24d 100644 --- a/base/ios/ios_util.mm +++ b/base/ios/ios_util.mm
@@ -20,10 +20,6 @@ namespace base { namespace ios { -bool IsRunningOnIOS7OrLater() { - return IsRunningOnOrLater(7, 0, 0); -} - bool IsRunningOnIOS8OrLater() { return IsRunningOnOrLater(8, 0, 0); }
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc index eef7f03..5d2fa2a 100644 --- a/base/memory/shared_memory_win.cc +++ b/base/memory/shared_memory_win.cc
@@ -118,8 +118,8 @@ return false; size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask; - name_ = ASCIIToWide(options.name_deprecated == NULL ? "" : - *options.name_deprecated); + name_ = options.name_deprecated ? + ASCIIToUTF16(*options.name_deprecated) : L""; SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE }; SECURITY_DESCRIPTOR sd; ACL dacl; @@ -137,10 +137,10 @@ // Windows ignores DACLs on certain unnamed objects (like shared sections). // So, we generate a random name when we need to enforce read-only. uint64_t rand_values[4]; - base::RandBytes(&rand_values, sizeof(rand_values)); - name_ = base::StringPrintf(L"CrSharedMem_%016x%016x%016x%016x", - rand_values[0], rand_values[1], - rand_values[2], rand_values[3]); + RandBytes(&rand_values, sizeof(rand_values)); + name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x", + rand_values[0], rand_values[1], + rand_values[2], rand_values[3]); } mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), name_.c_str()); @@ -171,7 +171,7 @@ bool SharedMemory::Open(const std::string& name, bool read_only) { DCHECK(!mapped_file_); - name_ = ASCIIToWide(name); + name_ = ASCIIToUTF16(name); read_only_ = read_only; mapped_file_ = OpenFileMapping( read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, @@ -218,7 +218,7 @@ } bool SharedMemory::ShareToProcessCommon(ProcessHandle process, - SharedMemoryHandle *new_handle, + SharedMemoryHandle* new_handle, bool close_self, ShareMode share_mode) { *new_handle = 0;
diff --git a/base/process/kill.h b/base/process/kill.h index de72d7a..f697701 100644 --- a/base/process/kill.h +++ b/base/process/kill.h
@@ -9,6 +9,7 @@ #define BASE_PROCESS_KILL_H_ #include "base/files/file_path.h" +#include "base/process/process.h" #include "base/process/process_handle.h" #include "base/time/time.h" @@ -146,10 +147,10 @@ // On Linux this method does not block the calling thread. // On OS X this method may block for up to 2 seconds. // -// NOTE: The process handle must have been opened with the PROCESS_TERMINATE -// and SYNCHRONIZE permissions. +// NOTE: The process must have been opened with the PROCESS_TERMINATE and +// SYNCHRONIZE permissions. // -BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle); +BASE_EXPORT void EnsureProcessTerminated(Process process); #if defined(OS_POSIX) && !defined(OS_MACOSX) // The nicer version of EnsureProcessTerminated() that is patient and will
diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc index 9257ee6..a2632f6 100644 --- a/base/process/kill_mac.cc +++ b/base/process/kill_mac.cc
@@ -165,8 +165,8 @@ } // namespace -void EnsureProcessTerminated(ProcessHandle process) { - WaitForChildToDie(process, kWaitBeforeKillSeconds); +void EnsureProcessTerminated(Process process) { + WaitForChildToDie(process.pid(), kWaitBeforeKillSeconds); } } // namespace base
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc index d17e990..3f304ca 100644 --- a/base/process/kill_posix.cc +++ b/base/process/kill_posix.cc
@@ -463,13 +463,13 @@ } // namespace -void EnsureProcessTerminated(ProcessHandle process) { +void EnsureProcessTerminated(Process process) { // If the child is already dead, then there's nothing to do. - if (IsChildDead(process)) + if (IsChildDead(process.pid())) return; const unsigned timeout = 2; // seconds - BackgroundReaper* reaper = new BackgroundReaper(process, timeout); + BackgroundReaper* reaper = new BackgroundReaper(process.pid(), timeout); PlatformThread::CreateNonJoinable(0, reaper); }
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc index b102a87..0a0c99c 100644 --- a/base/process/kill_win.cc +++ b/base/process/kill_win.cc
@@ -38,7 +38,7 @@ class TimerExpiredTask : public win::ObjectWatcher::Delegate { public: - explicit TimerExpiredTask(ProcessHandle process); + explicit TimerExpiredTask(Process process); ~TimerExpiredTask(); void TimedOut(); @@ -50,24 +50,23 @@ void KillProcess(); // The process that we are watching. - ProcessHandle process_; + Process process_; win::ObjectWatcher watcher_; DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask); }; -TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) { - watcher_.StartWatching(process_, this); +TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) { + watcher_.StartWatching(process_.Handle(), this); } TimerExpiredTask::~TimerExpiredTask() { TimedOut(); - DCHECK(!process_) << "Make sure to close the handle."; } void TimerExpiredTask::TimedOut() { - if (process_) + if (process_.IsValid()) KillProcess(); } @@ -76,8 +75,7 @@ tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION("TimerExpiredTask_OnObjectSignaled")); - CloseHandle(process_); - process_ = NULL; + process_.Close(); } void TimerExpiredTask::KillProcess() { @@ -88,10 +86,10 @@ // terminates. We just care that it eventually terminates, and that's what // TerminateProcess should do for us. Don't check for the result code since // it fails quite often. This should be investigated eventually. - base::KillProcess(process_, kProcessKilledExitCode, false); + base::KillProcess(process_.Handle(), kProcessKilledExitCode, false); // Now, just cleanup as if the process exited normally. - OnObjectSignaled(process_); + OnObjectSignaled(process_.Handle()); } } // namespace @@ -241,19 +239,18 @@ return false; } -void EnsureProcessTerminated(ProcessHandle process) { - DCHECK(process != GetCurrentProcess()); +void EnsureProcessTerminated(Process process) { + DCHECK(!process.is_current()); // If already signaled, then we are done! - if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { - CloseHandle(process); + if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) { return; } MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&TimerExpiredTask::TimedOut, - base::Owned(new TimerExpiredTask(process))), + base::Owned(new TimerExpiredTask(process.Pass()))), base::TimeDelta::FromMilliseconds(kWaitInterval)); }
diff --git a/base/process/launch.h b/base/process/launch.h index 06abb29..0450ddf 100644 --- a/base/process/launch.h +++ b/base/process/launch.h
@@ -22,7 +22,6 @@ #include "base/posix/file_descriptor_shuffle.h" #elif defined(OS_WIN) #include <windows.h> -#include "base/win/scoped_handle.h" #endif namespace base { @@ -174,9 +173,8 @@ // // Example (including literal quotes) // cmdline = "c:\windows\explorer.exe" -foo "c:\bar\" -BASE_EXPORT bool LaunchProcess(const string16& cmdline, - const LaunchOptions& options, - win::ScopedHandle* process_handle); +BASE_EXPORT Process LaunchProcess(const string16& cmdline, + const LaunchOptions& options); // Launches a process with elevated privileges. This does not behave exactly // like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index 3c787fe..1d83ef9 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc
@@ -232,6 +232,17 @@ return true; } +// TODO(rvargas) crbug.com/416721: Remove this stub after LaunchProcess is +// fully migrated to use Process. +Process LaunchProcess(const string16& cmdline, + const LaunchOptions& options) { + win::ScopedHandle process_handle; + if (LaunchProcess(cmdline, options, &process_handle)) + return Process(process_handle.Take()); + + return Process(); +} + bool LaunchProcess(const CommandLine& cmdline, const LaunchOptions& options, ProcessHandle* process_handle) {
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc index ea79d73..7afae21 100644 --- a/base/process/process_metrics_posix.cc +++ b/base/process/process_metrics_posix.cc
@@ -12,9 +12,8 @@ namespace base { int64 TimeValToMicroseconds(const struct timeval& tv) { - static const int kMicrosecondsPerSecond = 1000000; int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. - ret *= kMicrosecondsPerSecond; + ret *= Time::kMicrosecondsPerSecond; ret += tv.tv_usec; return ret; }
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc index c98884d..af88fe1 100644 --- a/base/process/process_util_unittest.cc +++ b/base/process/process_util_unittest.cc
@@ -888,14 +888,14 @@ } TEST_F(ProcessUtilTest, DelayedTermination) { - base::ProcessHandle child_process = SpawnChild("process_util_test_never_die"); - ASSERT_TRUE(child_process); - base::EnsureProcessTerminated(child_process); - base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5)); + base::Process child_process(SpawnChild("process_util_test_never_die")); + ASSERT_TRUE(child_process.IsValid()); + base::EnsureProcessTerminated(child_process.Duplicate()); + base::WaitForSingleProcess(child_process.Handle(), + base::TimeDelta::FromSeconds(5)); // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process)); - base::CloseProcessHandle(child_process); + EXPECT_TRUE(IsProcessDead(child_process.Handle())); } MULTIPROCESS_TEST_MAIN(process_util_test_never_die) { @@ -906,16 +906,14 @@ } TEST_F(ProcessUtilTest, ImmediateTermination) { - base::ProcessHandle child_process = - SpawnChild("process_util_test_die_immediately"); - ASSERT_TRUE(child_process); + base::Process child_process(SpawnChild("process_util_test_die_immediately")); + ASSERT_TRUE(child_process.IsValid()); // Give it time to die. sleep(2); - base::EnsureProcessTerminated(child_process); + base::EnsureProcessTerminated(child_process.Duplicate()); // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process)); - base::CloseProcessHandle(child_process); + EXPECT_TRUE(IsProcessDead(child_process.Handle())); } MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc index 02c75f9..ff05c6e 100644 --- a/base/strings/safe_sprintf_unittest.cc +++ b/base/strings/safe_sprintf_unittest.cc
@@ -61,7 +61,7 @@ // always add a trailing NUL; it always deduplicates '%' characters). static const char text[] = "hello world"; char ref[20], buf[20]; - memset(ref, 'X', sizeof(char) * arraysize(buf)); + memset(ref, 'X', sizeof(ref)); memcpy(buf, ref, sizeof(buf)); // A negative buffer size should always result in an error.
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc index 0d3eba9..707a4d7 100644 --- a/base/test/launcher/test_launcher.cc +++ b/base/test/launcher/test_launcher.cc
@@ -228,7 +228,7 @@ // on a CommandLine with a wrapper is known to break. // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. #if defined(OS_WIN) - new_command_line.PrependWrapper(ASCIIToWide(wrapper)); + new_command_line.PrependWrapper(ASCIIToUTF16(wrapper)); #elif defined(OS_POSIX) new_command_line.PrependWrapper(wrapper); #endif @@ -242,7 +242,7 @@ int LaunchChildTestProcessWithOptions(const CommandLine& command_line, const LaunchOptions& options, int flags, - base::TimeDelta timeout, + TimeDelta timeout, bool* was_timeout) { #if defined(OS_POSIX) // Make sure an option we rely on is present - see LaunchChildGTestProcess. @@ -287,7 +287,7 @@ new_options.allow_new_privs = true; #endif - base::ProcessHandle process_handle; + ProcessHandle process_handle; { // Note how we grab the lock before the process possibly gets created. @@ -295,21 +295,19 @@ // in the set. AutoLock lock(g_live_processes_lock.Get()); - if (!base::LaunchProcess(command_line, new_options, &process_handle)) + if (!LaunchProcess(command_line, new_options, &process_handle)) return -1; g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); } int exit_code = 0; - if (!base::WaitForExitCodeWithTimeout(process_handle, - &exit_code, - timeout)) { + if (!WaitForExitCodeWithTimeout(process_handle, &exit_code, timeout)) { *was_timeout = true; exit_code = -1; // Set a non-zero exit code to signal a failure. // Ensure that the process terminates. - base::KillProcess(process_handle, -1, true); + KillProcess(process_handle, -1, true); } { @@ -324,14 +322,14 @@ // or due to it timing out, we need to clean up any child processes that // it might have created. On Windows, child processes are automatically // cleaned up using JobObjects. - base::KillProcessGroup(process_handle); + KillProcessGroup(process_handle); } #endif g_live_processes.Get().erase(process_handle); } - base::CloseProcessHandle(process_handle); + CloseProcessHandle(process_handle); return exit_code; } @@ -347,7 +345,7 @@ void DoLaunchChildTestProcess( const CommandLine& command_line, - base::TimeDelta timeout, + TimeDelta timeout, int flags, bool redirect_stdio, scoped_refptr<MessageLoopProxy> message_loop_proxy, @@ -355,8 +353,8 @@ TimeTicks start_time = TimeTicks::Now(); // Redirect child process output to a file. - base::FilePath output_file; - CHECK(base::CreateTemporaryFile(&output_file)); + FilePath output_file; + CHECK(CreateTemporaryFile(&output_file)); LaunchOptions options; #if defined(OS_WIN) @@ -385,8 +383,8 @@ #elif defined(OS_POSIX) options.new_process_group = true; - base::FileHandleMappingVector fds_mapping; - base::ScopedFD output_file_fd; + FileHandleMappingVector fds_mapping; + ScopedFD output_file_fd; if (redirect_stdio) { output_file_fd.reset(open(output_file.value().c_str(), O_RDWR)); @@ -412,9 +410,9 @@ } std::string output_file_contents; - CHECK(base::ReadFileToString(output_file, &output_file_contents)); + CHECK(ReadFileToString(output_file, &output_file_contents)); - if (!base::DeleteFile(output_file, false)) { + if (!DeleteFile(output_file, false)) { // This needs to be non-fatal at least for Windows. LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); } @@ -519,7 +517,7 @@ void TestLauncher::LaunchChildGTestProcess( const CommandLine& command_line, const std::string& wrapper, - base::TimeDelta timeout, + TimeDelta timeout, int flags, const LaunchChildGTestProcessCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -945,10 +943,8 @@ if (excluded) continue; - if (base::Hash(test_name) % total_shards_ != - static_cast<uint32>(shard_index_)) { + if (Hash(test_name) % total_shards_ != static_cast<uint32>(shard_index_)) continue; - } test_names.push_back(test_name); }
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc index 2cbafef..e3b1ffc 100644 --- a/base/test/test_reg_util_win.cc +++ b/base/test/test_reg_util_win.cc
@@ -54,7 +54,7 @@ const base::Time& timestamp) { base::string16 key_path = test_key_root; key_path += L"\\" + base::Int64ToString16(timestamp.ToInternalValue()); - key_path += kTimestampDelimiter + base::ASCIIToWide(base::GenerateGUID()); + key_path += kTimestampDelimiter + base::ASCIIToUTF16(base::GenerateGUID()); return key_path; }
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium index dc8bdef..ff21b19 100644 --- a/base/third_party/dynamic_annotations/README.chromium +++ b/base/third_party/dynamic_annotations/README.chromium
@@ -3,6 +3,13 @@ Version: 4384 License: BSD +ATTENTION: please avoid using these annotations in Chromium code. +They were mainly intended to instruct the Valgrind-based version of +ThreadSanitizer to handle atomic operations. The new version of ThreadSanitizer +based on compiler instrumentation understands atomic operations out of the box, +so normally you don't need the annotations. +If you still think you do, please consider writing a comment at http://crbug.com/349861 + One header and one source file (dynamic_annotations.h and dynamic_annotations.c) in this directory define runtime macros useful for annotating synchronization utilities and benign data races so data race detectors can handle Chromium code
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py index e73d66c..39fe706 100644 --- a/build/android/pylib/device/adb_wrapper.py +++ b/build/android/pylib/device/adb_wrapper.py
@@ -161,8 +161,13 @@ timeout: (optional) Timeout per try in seconds. retries: (optional) Number of retries to attempt. """ - self._RunDeviceAdbCmd(['pull', remote, local], timeout, retries) - _VerifyLocalFileExists(local) + cmd = ['pull', remote, local] + self._RunDeviceAdbCmd(cmd, timeout, retries) + try: + _VerifyLocalFileExists(local) + except IOError: + raise device_errors.AdbCommandFailedError( + cmd, 'File not found on host: %s' % local, device_serial=str(self)) def Shell(self, command, expect_status=0, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py index 66a62fd..403f235 100644 --- a/build/android/pylib/device/device_utils.py +++ b/build/android/pylib/device/device_utils.py
@@ -855,11 +855,11 @@ CommandFailedError on failure. CommandTimeoutError on timeout. """ - try: - self.old_interface.PullFileFromDevice(device_path, host_path) - except AssertionError as e: - raise device_errors.CommandFailedError( - str(e), str(self)), None, sys.exc_info()[2] + # Create the base dir if it doesn't exist already + dirname = os.path.dirname(host_path) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + self.adb.Pull(device_path, host_path) @decorators.WithTimeoutAndRetriesFromInstance() def ReadFile(self, device_path, as_root=False, timeout=None, retries=None):
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py index 5f2249d..512a7d4 100755 --- a/build/android/pylib/device/device_utils_test.py +++ b/build/android/pylib/device/device_utils_test.py
@@ -1093,26 +1093,22 @@ self.assertFalse(self.device.FileExists('/does/not/exist')) -class DeviceUtilsPullFileTest(DeviceUtilsOldImplTest): +class DeviceUtilsPullFileTest(DeviceUtilsNewImplTest): def testPullFile_existsOnDevice(self): with mock.patch('os.path.exists', return_value=True): - with self.assertCallsSequence([ - ('adb -s 0123456789abcdef shell ' - 'ls /data/app/test.file.exists', - '/data/app/test.file.exists'), - ('adb -s 0123456789abcdef pull ' - '/data/app/test.file.exists /test/file/host/path', - '100 B/s (100 bytes in 1.000s)\r\n')]): + with self.assertCall( + self.call.adb.Pull('/data/app/test.file.exists', + '/test/file/host/path')): self.device.PullFile('/data/app/test.file.exists', '/test/file/host/path') def testPullFile_doesntExistOnDevice(self): with mock.patch('os.path.exists', return_value=True): - with self.assertCalls( - 'adb -s 0123456789abcdef shell ' - 'ls /data/app/test.file.does.not.exist', - '/data/app/test.file.does.not.exist: No such file or directory\r\n'): + with self.assertCall( + self.call.adb.Pull('/data/app/test.file.does.not.exist', + '/test/file/host/path'), + self.CommandError('remote object does not exist')): with self.assertRaises(device_errors.CommandFailedError): self.device.PullFile('/data/app/test.file.does.not.exist', '/test/file/host/path')
diff --git a/build/common.gypi b/build/common.gypi index 5a8f1b9..204a133 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -4185,13 +4185,6 @@ ], }], ], - 'conditions': [ - ['OS=="mac"', { - 'cflags': [ - '-mllvm -asan-globals=0', # http://crbug.com/352073 - ], - }], - ], }], ['ubsan==1', { 'target_conditions': [ @@ -4907,7 +4900,6 @@ 'xcode_settings': { 'OTHER_CFLAGS': [ '-fsanitize=address', - '-mllvm -asan-globals=0', # http://crbug.com/352073 '-gline-tables-only', ], },
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni index 3b2d76f..cb84879 100644 --- a/build/config/clang/clang.gni +++ b/build/config/clang/clang.gni
@@ -5,5 +5,5 @@ declare_args() { # Indicates if the build should use the Chrome-specific plugins for enforcing # coding guidelines, etc. Only used when compiling with Clang. - clang_use_chrome_plugins = is_clang + clang_use_chrome_plugins = is_clang && !is_nacl }
diff --git a/build/grit_action.gypi b/build/grit_action.gypi index ab7a70b..15ead28 100644 --- a/build/grit_action.gypi +++ b/build/grit_action.gypi
@@ -21,6 +21,20 @@ # instead of build/common.gypi . 'grit_additional_defines%': [], 'grit_rc_header_format%': [], + + 'conditions': [ + # These scripts can skip writing generated files if they are identical + # to the already existing files, which avoids further build steps, like + # recompilation. However, a dependency (earlier build step) having a + # newer timestamp than an output (later build step) confuses some build + # systems, so only use this on ninja, which explicitly supports this use + # case (gyp turns all actions into ninja restat rules). + ['"<(GENERATOR)"=="ninja"', { + 'write_only_new': '1', + }, { + 'write_only_new': '0', + }], + ], }, 'inputs': [ '<!@pymod_do_main(grit_info <@(grit_defines) <@(grit_additional_defines) ' @@ -35,6 +49,7 @@ '-i', '<(grit_grd_file)', 'build', '-f', '<(grit_resource_ids)', '-o', '<(grit_out_dir)', + '--write-only-new=<(write_only_new)', '<@(grit_defines)', '<@(grit_additional_defines)', '<@(grit_rc_header_format)'],
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt index 6fbe58d..17d9f89 100644 --- a/build/ios/grit_whitelist.txt +++ b/build/ios/grit_whitelist.txt
@@ -77,7 +77,6 @@ IDR_POLICY_HTML IDR_POLICY_JS IDR_PRINTER_FAVICON -IDR_PRODUCT_LOGO_26 IDR_SAD_FAVICON IDR_SAD_TAB IDR_SECURITY_INTERSTITIAL_HTML
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc index 821ba48..a3b05c1 100644 --- a/build/sanitizers/sanitizer_options.cc +++ b/build/sanitizers/sanitizer_options.cc
@@ -49,6 +49,8 @@ // fast_unwind_on_fatal=1 - use the fast (frame-pointer-based) stack unwinder // to print error reports. V8 doesn't generate debug info for the JIT code, // so the slow unwinder may not work properly. +// detect_stack_use_after_return=1 - use fake stack to delay the reuse of +// stack allocations and detect stack-use-after-return errors. #if defined(OS_LINUX) #if defined(GOOGLE_CHROME_BUILD) // Default AddressSanitizer options for the official build. These do not affect @@ -62,13 +64,14 @@ // Default AddressSanitizer options for buildbots and non-official builds. const char *kAsanDefaultOptions = "strict_memcmp=0 symbolize=false check_printf=1 use_sigaltstack=1 " - "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1"; + "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 " + "detect_stack_use_after_return=1 "; #endif // GOOGLE_CHROME_BUILD #elif defined(OS_MACOSX) const char *kAsanDefaultOptions = "strict_memcmp=0 replace_intrin=0 check_printf=1 use_sigaltstack=1 " - "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1"; + "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "; static const char kNaClDefaultOptions[] = "handle_segv=0"; static const char kNaClFlag[] = "--type=nacl-loader"; #endif // OS_LINUX
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 49e860d..7c10d6c 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -149,10 +149,6 @@ // http://crbug.com/285242 "race:media::PulseAudioOutputStream::SetVolume\n" -// http://crbug.com/290964 -"race:PostponeInterruptsScope\n" -"race:v8::internal::StackGuard::RequestInstallCode\n" - // http://crbug.com/296883 "race:net::URLFetcherCore::Stop\n"
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni index 9010abc..7a1cc26 100644 --- a/build/secondary/tools/grit/grit_rule.gni +++ b/build/secondary/tools/grit/grit_rule.gni
@@ -381,6 +381,7 @@ ".", "--depfile", rebase_path(depfile, root_build_dir), + "--write-only-new=1", ] + grit_defines # Add extra defines with -D flags.
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 7402509..0e1a6a3 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -436,6 +436,8 @@ "resources/tile_priority.h", "resources/tiling_set_eviction_queue.cc", "resources/tiling_set_eviction_queue.h", + "resources/tiling_set_raster_queue.cc", + "resources/tiling_set_raster_queue.h", "resources/transferable_resource.cc", "resources/transferable_resource.h", "resources/transform_display_item.cc",
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc index 3f01c54..4c8b49b 100644 --- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc +++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -130,13 +130,13 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) { LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1); ASSERT_TRUE(scroll_layer); - EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds()); + EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds()); EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation()); // Shrink along X axis, horizontal scrollbar should appear. clip_layer_->SetBounds(gfx::Size(100, 200)); - EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin(); @@ -148,7 +148,7 @@ // Shrink along Y axis and expand along X, horizontal scrollbar // should disappear. clip_layer_->SetBounds(gfx::Size(200, 100)); - EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin(); @@ -161,13 +161,13 @@ TEST_F(VerticalScrollbarAnimationControllerLinearFadeTest, HideOnResize) { LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1); ASSERT_TRUE(scroll_layer); - EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds()); + EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds()); EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation()); // Shrink along X axis, vertical scrollbar should remain invisible. clip_layer_->SetBounds(gfx::Size(100, 200)); - EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin(); @@ -178,7 +178,7 @@ // Shrink along Y axis and expand along X, vertical scrollbar should appear. clip_layer_->SetBounds(gfx::Size(200, 100)); - EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin();
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc index d46431b..74e9517 100644 --- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc +++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -85,13 +85,13 @@ TEST_F(ScrollbarAnimationControllerThinningTest, HideOnResize) { LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1); ASSERT_TRUE(scroll_layer); - EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds()); + EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds()); EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation()); // Shrink along X axis, horizontal scrollbar should appear. clip_layer_->SetBounds(gfx::Size(100, 200)); - EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin(); @@ -103,7 +103,7 @@ // Shrink along Y axis and expand along X, horizontal scrollbar // should disappear. clip_layer_->SetBounds(gfx::Size(200, 100)); - EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds()); + EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds()); scrollbar_controller_->DidScrollBegin();
diff --git a/cc/base/tiling_data_unittest.cc b/cc/base/tiling_data_unittest.cc index 667719b..732b04d 100644 --- a/cc/base/tiling_data_unittest.cc +++ b/cc/base/tiling_data_unittest.cc
@@ -775,26 +775,23 @@ TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsEmpty) { TilingData empty_total_size(gfx::Size(0, 0), gfx::Size(8, 8), true); - EXPECT_RECT_EQ( - gfx::Rect(), - empty_total_size.ExpandRectIgnoringBordersToTileBounds(gfx::Rect())); - EXPECT_RECT_EQ(gfx::Rect(), - empty_total_size.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect(100, 100, 100, 100))); - EXPECT_RECT_EQ(gfx::Rect(), - empty_total_size.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect(100, 100))); + EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect())); + EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect(100, 100, 100, 100))); + EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect(100, 100))); TilingData empty_max_texture_size(gfx::Size(8, 8), gfx::Size(0, 0), true); - EXPECT_RECT_EQ(gfx::Rect(), - empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect())); - EXPECT_RECT_EQ(gfx::Rect(), - empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect(100, 100, 100, 100))); - EXPECT_RECT_EQ(gfx::Rect(), - empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect(100, 100))); + EXPECT_EQ(gfx::Rect(), + empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect())); + EXPECT_EQ(gfx::Rect(), + empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect(100, 100, 100, 100))); + EXPECT_EQ(gfx::Rect(), + empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect(100, 100))); } TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) { @@ -804,8 +801,8 @@ gfx::Rect at_origin_src(1, 1); gfx::Rect at_origin_result(data.TileBounds(0, 0)); EXPECT_NE(at_origin_src, at_origin_result); - EXPECT_RECT_EQ(at_origin_result, - data.ExpandRectIgnoringBordersToTileBounds(at_origin_src)); + EXPECT_EQ(at_origin_result, + data.ExpandRectIgnoringBordersToTileBounds(at_origin_src)); // Arbitrary internal rect. gfx::Rect rect_src(6, 6, 1, 3); @@ -814,32 +811,30 @@ gfx::Rect rect_result( gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(2, 3))); EXPECT_NE(rect_src, rect_result); - EXPECT_RECT_EQ(rect_result, - data.ExpandRectIgnoringBordersToTileBounds(rect_src)); + EXPECT_EQ(rect_result, data.ExpandRectIgnoringBordersToTileBounds(rect_src)); // On tile bounds does not round up to next tile (ignores the border). gfx::Rect border_rect_src( gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4))); gfx::Rect border_rect_result( gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4))); - EXPECT_RECT_EQ(border_rect_result, - data.ExpandRectIgnoringBordersToTileBounds(border_rect_src)); + EXPECT_EQ(border_rect_result, + data.ExpandRectIgnoringBordersToTileBounds(border_rect_src)); // Equal to tiling rect. - EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()), - data.ExpandRectIgnoringBordersToTileBounds( - gfx::Rect(data.tiling_size()))); + EXPECT_EQ(gfx::Rect(data.tiling_size()), + data.ExpandRectIgnoringBordersToTileBounds( + gfx::Rect(data.tiling_size()))); // Containing, but larger than tiling rect. - EXPECT_RECT_EQ( - gfx::Rect(data.tiling_size()), - data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100))); + EXPECT_EQ(gfx::Rect(data.tiling_size()), + data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100))); // Non-intersecting with tiling rect. gfx::Rect non_intersect(200, 200, 100, 100); EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size()))); - EXPECT_RECT_EQ(gfx::Rect(), - data.ExpandRectIgnoringBordersToTileBounds(non_intersect)); + EXPECT_EQ(gfx::Rect(), + data.ExpandRectIgnoringBordersToTileBounds(non_intersect)); TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true); @@ -859,7 +854,7 @@ gfx::Rect at_origin_src(1, 1); gfx::Rect at_origin_result(data.TileBounds(0, 0)); EXPECT_NE(at_origin_src, at_origin_result); - EXPECT_RECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src)); + EXPECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src)); // Arbitrary internal rect. gfx::Rect rect_src(6, 6, 1, 3); @@ -868,28 +863,27 @@ gfx::Rect rect_result( gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(3, 4))); EXPECT_NE(rect_src, rect_result); - EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src)); + EXPECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src)); // On tile bounds rounds up to next tile (since border overlaps). gfx::Rect border_rect_src( gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4))); gfx::Rect border_rect_result( gfx::UnionRects(data.TileBounds(0, 1), data.TileBounds(4, 5))); - EXPECT_RECT_EQ(border_rect_result, - data.ExpandRectToTileBounds(border_rect_src)); + EXPECT_EQ(border_rect_result, data.ExpandRectToTileBounds(border_rect_src)); // Equal to tiling rect. - EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()), - data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size()))); + EXPECT_EQ(gfx::Rect(data.tiling_size()), + data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size()))); // Containing, but larger than tiling rect. - EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()), - data.ExpandRectToTileBounds(gfx::Rect(100, 100))); + EXPECT_EQ(gfx::Rect(data.tiling_size()), + data.ExpandRectToTileBounds(gfx::Rect(100, 100))); // Non-intersecting with tiling rect. gfx::Rect non_intersect(200, 200, 100, 100); EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size()))); - EXPECT_RECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect)); + EXPECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect)); TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true); @@ -953,17 +947,17 @@ EXPECT_EQ(35, data.TileSizeY(4)); EXPECT_EQ(5, data.num_tiles_y()); - EXPECT_RECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0)); - EXPECT_RECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1)); - EXPECT_RECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4)); - EXPECT_RECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2)); - EXPECT_RECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4)); + EXPECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0)); + EXPECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1)); + EXPECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4)); + EXPECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2)); + EXPECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4)); - EXPECT_RECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0)); - EXPECT_RECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1)); - EXPECT_RECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4)); - EXPECT_RECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2)); - EXPECT_RECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4)); + EXPECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0)); + EXPECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1)); + EXPECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4)); + EXPECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2)); + EXPECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4)); EXPECT_EQ(0, data.TileXIndexFromSrcCoord(0)); EXPECT_EQ(0, data.TileXIndexFromSrcCoord(69));
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn index 138be59..f95291a 100644 --- a/cc/blink/BUILD.gn +++ b/cc/blink/BUILD.gn
@@ -6,21 +6,6 @@ component("blink") { output_name = "cc_blink" - public_deps = [ - "//skia", - ] - deps = [ - "//base", - "//base/third_party/dynamic_annotations", - "//cc", - "//gpu", - "//third_party/WebKit/public:blink", - "//ui/gfx", - "//ui/gfx/geometry", - ] - - defines = [ "CC_BLINK_IMPLEMENTATION" ] - sources = [ "cc_blink_export.h", "scrollbar_impl.cc", @@ -64,12 +49,34 @@ "web_transform_operations_impl.cc", "web_transform_operations_impl.h", ] + + defines = [ "CC_BLINK_IMPLEMENTATION" ] + + public_deps = [ + "//skia", + ] + + deps = [ + "//base", + "//base/third_party/dynamic_annotations", + "//cc", + "//gpu", + "//third_party/WebKit/public:blink", + "//ui/gfx", + "//ui/gfx/geometry", + ] } # GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests # TODO(GYP): make linking work on the mac. if (!is_mac) { test("cc_blink_unittests") { + sources = [ + "web_animation_unittest.cc", + "web_float_animation_curve_unittest.cc", + "web_layer_impl_fixed_bounds_unittest.cc", + ] + deps = [ ":blink", "//base/test:run_all_unittests", @@ -81,11 +88,5 @@ "//cc", "//cc:test_support", ] - - sources = [ - "web_animation_unittest.cc", - "web_float_animation_curve_unittest.cc", - "web_layer_impl_fixed_bounds_unittest.cc", - ] } }
diff --git a/cc/blink/web_layer_impl_fixed_bounds_unittest.cc b/cc/blink/web_layer_impl_fixed_bounds_unittest.cc index ceeb311..083b0cf 100644 --- a/cc/blink/web_layer_impl_fixed_bounds_unittest.cc +++ b/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
@@ -53,9 +53,8 @@ original_point.y() * bounds.height / fixed_bounds.height(), original_point.z()); // Test if the bounds scale is correctly applied in transform. - EXPECT_POINT3F_EQ( - scaled_point, - TransformPoint(layer->layer()->transform(), original_point)); + EXPECT_EQ(scaled_point, + TransformPoint(layer->layer()->transform(), original_point)); } TEST(WebLayerImplFixedBoundsTest, BoundsScaleSimple) {
diff --git a/cc/cc.gyp b/cc/cc.gyp index 732bc0d..5967098 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp
@@ -472,6 +472,8 @@ 'resources/tile_priority.h', 'resources/tiling_set_eviction_queue.cc', 'resources/tiling_set_eviction_queue.h', + 'resources/tiling_set_raster_queue.cc', + 'resources/tiling_set_raster_queue.h', 'resources/transferable_resource.cc', 'resources/transferable_resource.h', 'resources/transform_display_item.cc',
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc index 54da888..6a38e4b 100644 --- a/cc/input/scroll_elasticity_helper.cc +++ b/cc/input/scroll_elasticity_helper.cc
@@ -32,6 +32,7 @@ } gfx::Vector2dF ScrollElasticityHelper::StretchAmount() { + // TODO(ccameron): Use the value of active_tree->elastic_overscroll directly return stretch_offset_; } @@ -63,7 +64,7 @@ gfx::Vector2dF ScrollElasticityHelper::AbsoluteScrollPosition() { // TODO(ccameron): This is function is redundant and may be removed. - return stretch_offset_; + return StretchAmount(); } void ScrollElasticityHelper::ImmediateScrollBy(const gfx::Vector2dF& scroll) { @@ -73,9 +74,14 @@ void ScrollElasticityHelper::ImmediateScrollByWithoutContentEdgeConstraints( const gfx::Vector2dF& scroll) { stretch_offset_ += scroll; - - // TODO(ccameron): Update the transform of the appropriate layer in the - // LayerTreeHostImpl, and request that a frame be drawn. + // TODO(ccameron): Use the value of active_tree->elastic_overscroll directly + // Note that this assumes that this property's true value is ever changed + // by the impl thread. While this is true, it is redundant state. + layer_tree_host_impl_->active_tree()->elastic_overscroll()->SetCurrent( + -stretch_offset_); + layer_tree_host_impl_->active_tree()->set_needs_update_draw_properties(); + layer_tree_host_impl_->SetNeedsCommit(); + layer_tree_host_impl_->SetNeedsRedraw(); } void ScrollElasticityHelper::StartSnapRubberbandTimer() {
diff --git a/cc/input/top_controls_manager_unittest.cc b/cc/input/top_controls_manager_unittest.cc index a209012..0be40ca 100644 --- a/cc/input/top_controls_manager_unittest.cc +++ b/cc/input/top_controls_manager_unittest.cc
@@ -32,7 +32,8 @@ top_controls_show_threshold_(top_controls_show_threshold), top_controls_hide_threshold_(top_controls_hide_threshold) { active_tree_ = - LayerTreeImpl::create(&host_impl_, new SyncedProperty<ScaleGroup>); + LayerTreeImpl::create(&host_impl_, new SyncedProperty<ScaleGroup>, + new SyncedElasticOverscroll); root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1); }
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc index f6262d3..c901a97 100644 --- a/cc/layers/nine_patch_layer_impl_unittest.cc +++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -80,7 +80,7 @@ // Check if the left-over quad is the same size as the mapped aperture quad in // layer space. if (!fill_center) { - EXPECT_RECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds())); + EXPECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds())); } else { EXPECT_TRUE(remaining.bounds().IsEmpty()); } @@ -97,7 +97,7 @@ } if (!fill_center) { - EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds()); + EXPECT_EQ(aperture_rect, tex_remaining.bounds()); Region aperture_region(aperture_rect); EXPECT_EQ(aperture_region, tex_remaining); } else {
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index eb90e95..6ec1f0a 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -106,6 +106,14 @@ new TilingSetEvictionQueue(tilings_.get(), tree_priority)); } +scoped_ptr<TilingSetRasterQueue> PictureLayerImpl::CreateRasterQueue( + bool prioritize_low_res) { + if (!tilings_) + return make_scoped_ptr(new TilingSetRasterQueue()); + return make_scoped_ptr( + new TilingSetRasterQueue(tilings_.get(), prioritize_low_res)); +} + const char* PictureLayerImpl::LayerTypeAsString() const { return "cc::PictureLayerImpl"; } @@ -1368,123 +1376,4 @@ &PictureLayerTiling::IsTileRequiredForDrawIfVisible); } -PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator() - : layer_(nullptr), current_stage_(arraysize(stages_)) { -} - -PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator( - PictureLayerImpl* layer, - bool prioritize_low_res) - : layer_(layer), current_stage_(0) { - DCHECK(layer_); - - // Early out if the layer has no tilings. - if (!layer_->tilings_ || !layer_->tilings_->num_tilings()) { - current_stage_ = arraysize(stages_); - return; - } - - // Tiles without valid priority are treated as having lowest priority and - // never considered for raster. - if (!layer_->HasValidTilePriorities()) { - current_stage_ = arraysize(stages_); - return; - } - - // Find high and low res tilings and initialize the iterators. - for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) { - PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i); - if (tiling->resolution() == HIGH_RESOLUTION) { - iterators_[HIGH_RES] = - PictureLayerTiling::TilingRasterTileIterator(tiling); - } - - if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) { - iterators_[LOW_RES] = - PictureLayerTiling::TilingRasterTileIterator(tiling); - } - } - - if (prioritize_low_res) { - stages_[0].iterator_type = LOW_RES; - stages_[0].tile_type = TilePriority::NOW; - - stages_[1].iterator_type = HIGH_RES; - stages_[1].tile_type = TilePriority::NOW; - } else { - stages_[0].iterator_type = HIGH_RES; - stages_[0].tile_type = TilePriority::NOW; - - stages_[1].iterator_type = LOW_RES; - stages_[1].tile_type = TilePriority::NOW; - } - - stages_[2].iterator_type = HIGH_RES; - stages_[2].tile_type = TilePriority::SOON; - - stages_[3].iterator_type = HIGH_RES; - stages_[3].tile_type = TilePriority::EVENTUALLY; - - IteratorType index = stages_[current_stage_].iterator_type; - TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; - if (!iterators_[index] || iterators_[index].get_type() != tile_type) - AdvanceToNextStage(); -} - -PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {} - -PictureLayerImpl::LayerRasterTileIterator::operator bool() const { - return current_stage_ < arraysize(stages_); -} - -PictureLayerImpl::LayerRasterTileIterator& -PictureLayerImpl::LayerRasterTileIterator:: -operator++() { - IteratorType index = stages_[current_stage_].iterator_type; - TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; - - // First advance the iterator. - DCHECK(iterators_[index]); - DCHECK(iterators_[index].get_type() == tile_type); - ++iterators_[index]; - - if (!iterators_[index] || iterators_[index].get_type() != tile_type) - AdvanceToNextStage(); - - return *this; -} - -Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() { - DCHECK(*this); - - IteratorType index = stages_[current_stage_].iterator_type; - DCHECK(iterators_[index]); - DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type); - - return *iterators_[index]; -} - -const Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() const { - DCHECK(*this); - - IteratorType index = stages_[current_stage_].iterator_type; - DCHECK(iterators_[index]); - DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type); - - return *iterators_[index]; -} - -void PictureLayerImpl::LayerRasterTileIterator::AdvanceToNextStage() { - DCHECK_LT(current_stage_, arraysize(stages_)); - ++current_stage_; - while (current_stage_ < arraysize(stages_)) { - IteratorType index = stages_[current_stage_].iterator_type; - TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; - - if (iterators_[index] && iterators_[index].get_type() == tile_type) - break; - ++current_stage_; - } -} - } // namespace cc
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index 52d8433..ddf928b 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -16,6 +16,7 @@ #include "cc/resources/picture_layer_tiling_set.h" #include "cc/resources/picture_pile_impl.h" #include "cc/resources/tiling_set_eviction_queue.h" +#include "cc/resources/tiling_set_raster_queue.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPicture.h" @@ -38,36 +39,6 @@ PictureLayerImpl* pending; }; - class CC_EXPORT LayerRasterTileIterator { - public: - LayerRasterTileIterator(); - LayerRasterTileIterator(PictureLayerImpl* layer, bool prioritize_low_res); - ~LayerRasterTileIterator(); - - Tile* operator*(); - const Tile* operator*() const; - LayerRasterTileIterator& operator++(); - operator bool() const; - - private: - enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS }; - - void AdvanceToNextStage(); - - PictureLayerImpl* layer_; - - struct IterationStage { - IteratorType iterator_type; - TilePriority::PriorityBin tile_type; - }; - - size_t current_stage_; - - // One low res stage, and three high res stages. - IterationStage stages_[4]; - PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS]; - }; - static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) { return make_scoped_ptr(new PictureLayerImpl(tree_impl, id)); } @@ -75,6 +46,7 @@ scoped_ptr<TilingSetEvictionQueue> CreateEvictionQueue( TreePriority tree_priority); + scoped_ptr<TilingSetRasterQueue> CreateRasterQueue(bool prioritize_low_res); // LayerImpl overrides. const char* LayerTypeAsString() const override;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc index bfb5703..074467f 100644 --- a/cc/layers/picture_layer_impl_perftest.cc +++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -67,21 +67,21 @@ pending_layer_->DoPostCommitInitializationIfNeeded(); } - void RunRasterIteratorConstructAndIterateTest( - const std::string& test_name, - int num_tiles, - const gfx::Size& viewport_size) { + void RunRasterQueueConstructAndIterateTest(const std::string& test_name, + int num_tiles, + const gfx::Size& viewport_size) { host_impl_.SetViewportSize(viewport_size); host_impl_.pending_tree()->UpdateDrawProperties(); timer_.Reset(); do { int count = num_tiles; - PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false); + scoped_ptr<TilingSetRasterQueue> queue = + pending_layer_->CreateRasterQueue(false); while (count--) { - ASSERT_TRUE(it) << "count: " << count; - ASSERT_TRUE(*it != nullptr) << "count: " << count; - ++it; + ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count; + ASSERT_TRUE(queue->Top() != nullptr) << "count: " << count; + queue->Pop(); } timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -94,8 +94,8 @@ true); } - void RunRasterIteratorConstructTest(const std::string& test_name, - const gfx::Rect& viewport) { + void RunRasterQueueConstructTest(const std::string& test_name, + const gfx::Rect& viewport) { host_impl_.SetViewportSize(viewport.size()); pending_layer_->SetScrollOffset( gfx::ScrollOffset(viewport.x(), viewport.y())); @@ -103,7 +103,8 @@ timer_.Reset(); do { - PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false); + scoped_ptr<TilingSetRasterQueue> queue = + pending_layer_->CreateRasterQueue(false); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -186,6 +187,7 @@ DISALLOW_COPY_AND_ASSIGN(PictureLayerImplPerfTest); }; +// TODO(vmpstr): Rename these tests once the perf numbers are in. TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstructAndIterate) { SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); @@ -197,16 +199,13 @@ pending_layer_->AddTiling(1.0f); pending_layer_->AddTiling(2.0f); - RunRasterIteratorConstructAndIterateTest( - "32_100x100", 32, gfx::Size(100, 100)); - RunRasterIteratorConstructAndIterateTest( - "32_500x500", 32, gfx::Size(500, 500)); - RunRasterIteratorConstructAndIterateTest( - "64_100x100", 64, gfx::Size(100, 100)); - RunRasterIteratorConstructAndIterateTest( - "64_500x500", 64, gfx::Size(500, 500)); + RunRasterQueueConstructAndIterateTest("32_100x100", 32, gfx::Size(100, 100)); + RunRasterQueueConstructAndIterateTest("32_500x500", 32, gfx::Size(500, 500)); + RunRasterQueueConstructAndIterateTest("64_100x100", 64, gfx::Size(100, 100)); + RunRasterQueueConstructAndIterateTest("64_500x500", 64, gfx::Size(500, 500)); } +// TODO(vmpstr): Rename these tests once the perf numbers are in. TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstruct) { SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); @@ -218,11 +217,9 @@ pending_layer_->AddTiling(1.0f); pending_layer_->AddTiling(2.0f); - RunRasterIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100)); - RunRasterIteratorConstructTest("5000_0_100x100", - gfx::Rect(5000, 0, 100, 100)); - RunRasterIteratorConstructTest("9999_0_100x100", - gfx::Rect(9999, 0, 100, 100)); + RunRasterQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100)); + RunRasterQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100)); + RunRasterQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100)); } // TODO(e_hakkinen): Rename these tests once the perf numbers are in.
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 7c2dbcb..4d3b751 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2775,7 +2775,7 @@ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f); } -TEST_F(PictureLayerImplTest, LayerRasterTileIterator) { +TEST_F(PictureLayerImplTest, TilingSetRasterQueue) { base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( @@ -2793,13 +2793,10 @@ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; - // Empty iterator - PictureLayerImpl::LayerRasterTileIterator it; - EXPECT_FALSE(it); - // No tilings. - it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - EXPECT_FALSE(it); + scoped_ptr<TilingSetRasterQueue> queue = + pending_layer_->CreateRasterQueue(false); + EXPECT_TRUE(queue->IsEmpty()); pending_layer_->AddTiling(low_res_factor); pending_layer_->AddTiling(0.3f); @@ -2815,10 +2812,9 @@ size_t non_ideal_tile_count = 0u; size_t low_res_tile_count = 0u; size_t high_res_tile_count = 0u; - for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - it; - ++it) { - Tile* tile = *it; + queue = pending_layer_->CreateRasterQueue(false); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); TilePriority priority = tile->priority(PENDING_TREE); EXPECT_TRUE(tile); @@ -2837,6 +2833,7 @@ high_res_tile_count += priority.resolution == HIGH_RESOLUTION; unique_tiles.insert(tile); + queue->Pop(); } EXPECT_TRUE(reached_prepaint); @@ -2858,10 +2855,9 @@ unique_tiles.clear(); high_res_tile_count = 0u; - for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - it; - ++it) { - Tile* tile = *it; + queue = pending_layer_->CreateRasterQueue(false); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); TilePriority priority = tile->priority(PENDING_TREE); EXPECT_TRUE(tile); @@ -2873,6 +2869,7 @@ high_res_tile_count += priority.resolution == HIGH_RESOLUTION; unique_tiles.insert(tile); + queue->Pop(); } EXPECT_EQ(16u, high_res_tile_count); @@ -2898,9 +2895,9 @@ non_ideal_tile_count = 0; low_res_tile_count = 0; high_res_tile_count = 0; - for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, true); it; - ++it) { - Tile* tile = *it; + queue = pending_layer_->CreateRasterQueue(true); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); TilePriority priority = tile->priority(PENDING_TREE); EXPECT_TRUE(tile); @@ -2908,6 +2905,7 @@ non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION; low_res_tile_count += priority.resolution == LOW_RESOLUTION; high_res_tile_count += priority.resolution == HIGH_RESOLUTION; + queue->Pop(); } EXPECT_EQ(0u, non_ideal_tile_count); @@ -3923,11 +3921,10 @@ // No occlusion. int unoccluded_tile_count = 0; - for (PictureLayerImpl::LayerRasterTileIterator it = - PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - it; - ++it) { - Tile* tile = *it; + scoped_ptr<TilingSetRasterQueue> queue = + pending_layer_->CreateRasterQueue(false); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); // Occluded tiles should not be iterated over. EXPECT_FALSE(tile->is_occluded(PENDING_TREE)); @@ -3938,6 +3935,7 @@ tile->content_rect().Intersects(pending_layer_->visible_content_rect()); if (tile_is_visible) unoccluded_tile_count++; + queue->Pop(); } EXPECT_EQ(unoccluded_tile_count, 25); @@ -3956,11 +3954,9 @@ host_impl_.pending_tree()->UpdateDrawProperties(); unoccluded_tile_count = 0; - for (PictureLayerImpl::LayerRasterTileIterator it = - PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - it; - ++it) { - Tile* tile = *it; + queue = pending_layer_->CreateRasterQueue(false); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); EXPECT_FALSE(tile->is_occluded(PENDING_TREE)); @@ -3968,6 +3964,7 @@ tile->content_rect().Intersects(pending_layer_->visible_content_rect()); if (tile_is_visible) unoccluded_tile_count++; + queue->Pop(); } EXPECT_EQ(20, unoccluded_tile_count); @@ -3980,11 +3977,9 @@ host_impl_.pending_tree()->UpdateDrawProperties(); unoccluded_tile_count = 0; - for (PictureLayerImpl::LayerRasterTileIterator it = - PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false); - it; - ++it) { - Tile* tile = *it; + queue = pending_layer_->CreateRasterQueue(false); + while (!queue->IsEmpty()) { + Tile* tile = queue->Top(); EXPECT_FALSE(tile->is_occluded(PENDING_TREE)); @@ -3992,6 +3987,7 @@ tile->content_rect().Intersects(pending_layer_->visible_content_rect()); if (tile_is_visible) unoccluded_tile_count++; + queue->Pop(); } EXPECT_EQ(unoccluded_tile_count, 0); }
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc index 8175efa..6a3e168 100644 --- a/cc/layers/render_surface_unittest.cc +++ b/cc/layers/render_surface_unittest.cc
@@ -131,8 +131,7 @@ EXPECT_EQ( 40.0, shared_quad_state->content_to_target_transform.matrix().getDouble(1, 3)); - EXPECT_RECT_EQ(content_rect, - gfx::Rect(shared_quad_state->visible_content_rect)); + EXPECT_EQ(content_rect, gfx::Rect(shared_quad_state->visible_content_rect)); EXPECT_EQ(1.f, shared_quad_state->opacity); EXPECT_EQ(blend_mode, shared_quad_state->blend_mode); } @@ -182,7 +181,7 @@ RenderPass* pass = pass_sink.RenderPasses()[0]; EXPECT_EQ(RenderPassId(2, 0), pass->id); - EXPECT_RECT_EQ(content_rect, pass->output_rect); + EXPECT_EQ(content_rect, pass->output_rect); EXPECT_EQ(origin, pass->transform_to_root_target); }
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index 8a998f3..09de7d0 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -352,7 +352,7 @@ const QuadList& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material); - EXPECT_RECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect); + EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect); } // Contents scale should scale the draw quad. @@ -366,7 +366,7 @@ const QuadList& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material); - EXPECT_RECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect); + EXPECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect); } scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f; scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f; @@ -382,7 +382,7 @@ const QuadList& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material); - EXPECT_RECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect); + EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect); } // We shouldn't attempt div-by-zero when the maximum is zero. @@ -396,7 +396,7 @@ const QuadList& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material); - EXPECT_RECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect); + EXPECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect); } } @@ -455,7 +455,7 @@ const QuadList& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material); - EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect); + EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect); } } @@ -544,10 +544,10 @@ layers[0]->SetBounds(gfx::Size(100, 3)); layers[1]->SetBounds(gfx::Size(3, 100)); - EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f), - horizontal_scrollbar_layer_->ComputeThumbQuadRect()); - EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f), - vertical_scrollbar_layer_->ComputeThumbQuadRect()); + EXPECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f), + horizontal_scrollbar_layer_->ComputeThumbQuadRect()); + EXPECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f), + vertical_scrollbar_layer_->ComputeThumbQuadRect()); horizontal_scrollbar_layer_->SetVerticalAdjust(10.f); vertical_scrollbar_layer_->SetVerticalAdjust(10.f); @@ -556,10 +556,10 @@ // 1.) Moves the horizontal scrollbar down // 2.) Increases the vertical scrollbar's effective track length which both // increases the thumb's length and its position within the track. - EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f), - horizontal_scrollbar_layer_->ComputeThumbQuadRect()); - EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f), - vertical_scrollbar_layer_->ComputeThumbQuadRect()); + EXPECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f), + horizontal_scrollbar_layer_->ComputeThumbQuadRect()); + EXPECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f), + vertical_scrollbar_layer_->ComputeThumbQuadRect()); } class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc index 512fa51..a9a1e78 100644 --- a/cc/layers/tiled_layer_unittest.cc +++ b/cc/layers/tiled_layer_unittest.cc
@@ -1711,7 +1711,7 @@ layer->Update(queue_.get(), nullptr); layer->tracking_layer_painter()->ResetPaintedRect(); - EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect()); + EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect()); UpdateTextures(); // Invalidate the entire layer in content space. When painting, the rect given @@ -1722,8 +1722,8 @@ // Rounding leads to an extra pixel. gfx::Rect expanded_layer_rect(layer_rect); expanded_layer_rect.set_height(32); - EXPECT_RECT_EQ(expanded_layer_rect, - layer->tracking_layer_painter()->PaintedRect()); + EXPECT_EQ(expanded_layer_rect, + layer->tracking_layer_painter()->PaintedRect()); } TEST_F(TiledLayerTest, @@ -1750,7 +1750,7 @@ layer->Update(queue_.get(), nullptr); layer->tracking_layer_painter()->ResetPaintedRect(); - EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect()); + EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect()); UpdateTextures(); // Invalidate the entire layer in layer space. When painting, the rect given @@ -1761,8 +1761,8 @@ // Rounding leads to an extra pixel. gfx::Rect expanded_layer_rect(layer_rect); expanded_layer_rect.set_height(32); - EXPECT_RECT_EQ(expanded_layer_rect, - layer->tracking_layer_painter()->PaintedRect()); + EXPECT_EQ(expanded_layer_rect, + layer->tracking_layer_painter()->PaintedRect()); } } // namespace
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc index bb7451d..c98b3e8 100644 --- a/cc/output/overlay_unittest.cc +++ b/cc/output/overlay_unittest.cc
@@ -205,10 +205,10 @@ RenderPass* actual = actual_list[i]; EXPECT_EQ(expected->id, actual->id); - EXPECT_RECT_EQ(expected->output_rect, actual->output_rect); + EXPECT_EQ(expected->output_rect, actual->output_rect); EXPECT_EQ(expected->transform_to_root_target, actual->transform_to_root_target); - EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect); + EXPECT_EQ(expected->damage_rect, actual->damage_rect); EXPECT_EQ(expected->has_transparent_background, actual->has_transparent_background);
diff --git a/cc/quads/draw_polygon_unittest.cc b/cc/quads/draw_polygon_unittest.cc index 27cfed4..360a014 100644 --- a/cc/quads/draw_polygon_unittest.cc +++ b/cc/quads/draw_polygon_unittest.cc
@@ -19,16 +19,11 @@ #define EXPECT_FLOAT_WITHIN_EPSILON_OF(a, b) \ EXPECT_TRUE(std::abs(a - b) < std::numeric_limits<float>::epsilon()); -#define EXPECT_POINT_EQ(point_a, point_b) \ - EXPECT_FLOAT_EQ(point_a.x(), point_b.x()); \ - EXPECT_FLOAT_EQ(point_a.y(), point_b.y()); \ - EXPECT_FLOAT_EQ(point_a.z(), point_b.z()); - static void ValidatePoints(const DrawPolygon& polygon, const std::vector<gfx::Point3F>& points) { EXPECT_EQ(polygon.points().size(), points.size()); for (size_t i = 0; i < points.size(); i++) { - EXPECT_POINT_EQ(polygon.points()[i], points[i]); + EXPECT_EQ(polygon.points()[i], points[i]); } }
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc index 95c646b..e65b326 100644 --- a/cc/quads/draw_quad_unittest.cc +++ b/cc/quads/draw_quad_unittest.cc
@@ -55,9 +55,9 @@ scoped_ptr<SharedQuadState> copy(new SharedQuadState); copy->CopyFrom(state.get()); EXPECT_EQ(quad_transform, copy->content_to_target_transform); - EXPECT_RECT_EQ(visible_content_rect, copy->visible_content_rect); + EXPECT_EQ(visible_content_rect, copy->visible_content_rect); EXPECT_EQ(opacity, copy->opacity); - EXPECT_RECT_EQ(clip_rect, copy->clip_rect); + EXPECT_EQ(clip_rect, copy->clip_rect); EXPECT_EQ(is_clipped, copy->is_clipped); EXPECT_EQ(blend_mode, copy->blend_mode); } @@ -88,9 +88,9 @@ DrawQuad* copy, SharedQuadState* copy_shared_state) { EXPECT_EQ(quad->material, copy->material); - EXPECT_RECT_EQ(quad->rect, copy->rect); - EXPECT_RECT_EQ(quad->visible_rect, copy->visible_rect); - EXPECT_RECT_EQ(quad->opaque_rect, copy->opaque_rect); + EXPECT_EQ(quad->rect, copy->rect); + EXPECT_EQ(quad->visible_rect, copy->visible_rect); + EXPECT_EQ(quad->opaque_rect, copy->opaque_rect); EXPECT_EQ(quad->needs_blending, copy->needs_blending); EXPECT_EQ(copy_shared_state, copy->shared_quad_state); } @@ -373,7 +373,7 @@ CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color); EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(color, copy_quad->color); CREATE_QUAD_1_ALL(CheckerboardDrawQuad, color); @@ -389,7 +389,7 @@ CREATE_QUAD_3_NEW(DebugBorderDrawQuad, visible_rect, color, width); EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(color, copy_quad->color); EXPECT_EQ(width, copy_quad->width); @@ -414,8 +414,8 @@ resource_id, orientation); EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); EXPECT_EQ(size, copy_quad->io_surface_size); EXPECT_EQ(resource_id, copy_quad->io_surface_resource_id); EXPECT_EQ(orientation, copy_quad->orientation); @@ -454,7 +454,7 @@ background_filters, copied_render_pass_id); EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id); EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id); EXPECT_EQ(mask_uv_scale.ToString(), copy_quad->mask_uv_scale.ToString()); @@ -493,7 +493,7 @@ CREATE_QUAD_3_NEW( SolidColorDrawQuad, visible_rect, color, force_anti_aliasing_off); EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(color, copy_quad->color); EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off); @@ -513,8 +513,8 @@ CREATE_QUAD_4_NEW( StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix); EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); EXPECT_EQ(resource_id, copy_quad->resource_id); EXPECT_EQ(matrix, copy_quad->matrix); @@ -531,7 +531,7 @@ CREATE_QUAD_2_NEW(SurfaceDrawQuad, visible_rect, surface_id); EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(surface_id, copy_quad->surface_id); CREATE_QUAD_1_ALL(SurfaceDrawQuad, surface_id); @@ -564,8 +564,8 @@ flipped, nearest_neighbor); EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); EXPECT_EQ(resource_id, copy_quad->resource_id); EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha); EXPECT_EQ(uv_top_left, copy_quad->uv_top_left); @@ -610,8 +610,8 @@ texture_size, swizzle_contents); EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(resource_id, copy_quad->resource_id); EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect); EXPECT_EQ(texture_size, copy_quad->texture_size); @@ -650,8 +650,8 @@ a_plane_resource_id, color_space); EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect); EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id); EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id); @@ -690,12 +690,12 @@ texture_size, texture_format, content_rect, contents_scale, raster_source); EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material); - EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect); - EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect); + EXPECT_EQ(opaque_rect, copy_quad->opaque_rect); + EXPECT_EQ(visible_rect, copy_quad->visible_rect); EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect); EXPECT_EQ(texture_size, copy_quad->texture_size); EXPECT_EQ(texture_format, copy_quad->texture_format); - EXPECT_RECT_EQ(content_rect, copy_quad->content_rect); + EXPECT_EQ(content_rect, copy_quad->content_rect); EXPECT_EQ(contents_scale, copy_quad->contents_scale); EXPECT_EQ(raster_source, copy_quad->raster_source); @@ -706,7 +706,7 @@ EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect); EXPECT_EQ(texture_size, copy_quad->texture_size); EXPECT_EQ(texture_format, copy_quad->texture_format); - EXPECT_RECT_EQ(content_rect, copy_quad->content_rect); + EXPECT_EQ(content_rect, copy_quad->content_rect); EXPECT_EQ(contents_scale, copy_quad->contents_scale); EXPECT_EQ(raster_source, copy_quad->raster_source); }
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc index 4c3753f..8775d81 100644 --- a/cc/quads/render_pass_unittest.cc +++ b/cc/quads/render_pass_unittest.cc
@@ -41,10 +41,10 @@ RenderPass* actual = actual_list[i]; EXPECT_EQ(expected->id, actual->id); - EXPECT_RECT_EQ(expected->output_rect, actual->output_rect); + EXPECT_EQ(expected->output_rect, actual->output_rect); EXPECT_EQ(expected->transform_to_root_target, actual->transform_to_root_target); - EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect); + EXPECT_EQ(expected->damage_rect, actual->damage_rect); EXPECT_EQ(expected->has_transparent_background, actual->has_transparent_background); @@ -99,9 +99,9 @@ scoped_ptr<RenderPass> copy = pass->Copy(new_id); EXPECT_EQ(new_id, copy->id); - EXPECT_RECT_EQ(pass->output_rect, copy->output_rect); + EXPECT_EQ(pass->output_rect, copy->output_rect); EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target); - EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect); + EXPECT_EQ(pass->damage_rect, copy->damage_rect); EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background); EXPECT_EQ(0u, copy->quad_list.size());
diff --git a/cc/resources/raster_tile_priority_queue.cc b/cc/resources/raster_tile_priority_queue.cc index 667d54d..9b7942d 100644 --- a/cc/resources/raster_tile_priority_queue.cc +++ b/cc/resources/raster_tile_priority_queue.cc
@@ -14,8 +14,8 @@ : tree_priority_(tree_priority) {} bool operator()( - const RasterTilePriorityQueue::PairedPictureLayerQueue* a, - const RasterTilePriorityQueue::PairedPictureLayerQueue* b) const { + const RasterTilePriorityQueue::PairedTilingSetQueue* a, + const RasterTilePriorityQueue::PairedTilingSetQueue* b) const { // Note that in this function, we have to return true if and only if // a is strictly lower priority than b. Note that for the sake of // completeness, empty queue is considered to have lowest priority. @@ -23,15 +23,15 @@ return b->IsEmpty() < a->IsEmpty(); WhichTree a_tree = a->NextTileIteratorTree(tree_priority_); - const PictureLayerImpl::LayerRasterTileIterator* a_iterator = - a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator; + const auto* a_queue = + a_tree == ACTIVE_TREE ? a->active_queue.get() : a->pending_queue.get(); WhichTree b_tree = b->NextTileIteratorTree(tree_priority_); - const PictureLayerImpl::LayerRasterTileIterator* b_iterator = - b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator; + const auto* b_queue = + b_tree == ACTIVE_TREE ? b->active_queue.get() : b->pending_queue.get(); - const Tile* a_tile = **a_iterator; - const Tile* b_tile = **b_iterator; + const Tile* a_tile = a_queue->Top(); + const Tile* b_tile = b_queue->Top(); const TilePriority& a_priority = a_tile->priority_for_tree_priority(tree_priority_); @@ -80,15 +80,15 @@ TreePriority tree_priority_; }; -WhichTree HigherPriorityTree( - TreePriority tree_priority, - const PictureLayerImpl::LayerRasterTileIterator* active_iterator, - const PictureLayerImpl::LayerRasterTileIterator* pending_iterator, - const Tile* shared_tile) { +WhichTree HigherPriorityTree(TreePriority tree_priority, + const TilingSetRasterQueue* active_queue, + const TilingSetRasterQueue* pending_queue, + const Tile* shared_tile) { switch (tree_priority) { case SMOOTHNESS_TAKES_PRIORITY: { - const Tile* active_tile = shared_tile ? shared_tile : **active_iterator; - const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator; + const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top(); + const Tile* pending_tile = + shared_tile ? shared_tile : pending_queue->Top(); const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); const TilePriority& pending_priority = @@ -106,8 +106,9 @@ case NEW_CONTENT_TAKES_PRIORITY: return PENDING_TREE; case SAME_PRIORITY_FOR_BOTH_TREES: { - const Tile* active_tile = shared_tile ? shared_tile : **active_iterator; - const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator; + const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top(); + const Tile* pending_tile = + shared_tile ? shared_tile : pending_queue->Top(); const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); const TilePriority& pending_priority = @@ -140,7 +141,7 @@ it != paired_layers.end(); ++it) { paired_queues_.push_back( - make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_))); + make_scoped_ptr(new PairedTilingSetQueue(*it, tree_priority_))); } paired_queues_.make_heap(RasterOrderComparator(tree_priority_)); } @@ -162,72 +163,70 @@ DCHECK(!IsEmpty()); paired_queues_.pop_heap(RasterOrderComparator(tree_priority_)); - PairedPictureLayerQueue* paired_queue = paired_queues_.back(); + PairedTilingSetQueue* paired_queue = paired_queues_.back(); paired_queue->Pop(tree_priority_); paired_queues_.push_heap(RasterOrderComparator(tree_priority_)); } -RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() { +RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() { } -RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue( +RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue( const PictureLayerImpl::Pair& layer_pair, TreePriority tree_priority) - : active_iterator(layer_pair.active - ? PictureLayerImpl::LayerRasterTileIterator( - layer_pair.active, - tree_priority == SMOOTHNESS_TAKES_PRIORITY) - : PictureLayerImpl::LayerRasterTileIterator()), - pending_iterator(layer_pair.pending - ? PictureLayerImpl::LayerRasterTileIterator( - layer_pair.pending, - tree_priority == SMOOTHNESS_TAKES_PRIORITY) - : PictureLayerImpl::LayerRasterTileIterator()), - has_both_layers(layer_pair.active && layer_pair.pending) { + : has_both_layers(layer_pair.active && layer_pair.pending) { + if (layer_pair.active) { + active_queue = layer_pair.active->CreateRasterQueue( + tree_priority == SMOOTHNESS_TAKES_PRIORITY); + } + + if (layer_pair.pending) { + pending_queue = layer_pair.pending->CreateRasterQueue( + tree_priority == SMOOTHNESS_TAKES_PRIORITY); + } + if (has_both_layers) SkipTilesReturnedByTwin(tree_priority); + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "PairedPictureLayerQueue::PairedPictureLayerQueue", - TRACE_EVENT_SCOPE_THREAD, - "state", - StateAsValue()); + "PairedTilingSetQueue::PairedTilingSetQueue", + TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); } -RasterTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() { +RasterTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() { TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "PairedPictureLayerQueue::~PairedPictureLayerQueue", - TRACE_EVENT_SCOPE_THREAD, - "state", - StateAsValue()); + "PairedTilingSetQueue::~PairedTilingSetQueue", + TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); } -bool RasterTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const { - return !active_iterator && !pending_iterator; +bool RasterTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const { + return (!active_queue || active_queue->IsEmpty()) && + (!pending_queue || pending_queue->IsEmpty()); } -Tile* RasterTilePriorityQueue::PairedPictureLayerQueue::Top( +Tile* RasterTilePriorityQueue::PairedTilingSetQueue::Top( TreePriority tree_priority) { DCHECK(!IsEmpty()); WhichTree next_tree = NextTileIteratorTree(tree_priority); - PictureLayerImpl::LayerRasterTileIterator* next_iterator = - next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; - DCHECK(*next_iterator); - Tile* tile = **next_iterator; + TilingSetRasterQueue* next_queue = + next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get(); + DCHECK(next_queue && !next_queue->IsEmpty()); + Tile* tile = next_queue->Top(); DCHECK(returned_tiles_for_debug.find(tile) == returned_tiles_for_debug.end()); return tile; } -void RasterTilePriorityQueue::PairedPictureLayerQueue::Pop( +void RasterTilePriorityQueue::PairedTilingSetQueue::Pop( TreePriority tree_priority) { DCHECK(!IsEmpty()); WhichTree next_tree = NextTileIteratorTree(tree_priority); - PictureLayerImpl::LayerRasterTileIterator* next_iterator = - next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; - DCHECK(*next_iterator); - DCHECK(returned_tiles_for_debug.insert(**next_iterator).second); - ++(*next_iterator); + TilingSetRasterQueue* next_queue = + next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get(); + DCHECK(next_queue && !next_queue->IsEmpty()); + DCHECK(returned_tiles_for_debug.insert(next_queue->Top()).second); + next_queue->Pop(); if (has_both_layers) SkipTilesReturnedByTwin(tree_priority); @@ -236,17 +235,18 @@ DCHECK(IsEmpty() || Top(tree_priority)); } -void RasterTilePriorityQueue::PairedPictureLayerQueue::SkipTilesReturnedByTwin( +void RasterTilePriorityQueue::PairedTilingSetQueue::SkipTilesReturnedByTwin( TreePriority tree_priority) { // We have both layers (active and pending) thus we can encounter shared // tiles twice (from the active iterator and from the pending iterator). while (!IsEmpty()) { WhichTree next_tree = NextTileIteratorTree(tree_priority); - PictureLayerImpl::LayerRasterTileIterator* next_iterator = - next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator; + TilingSetRasterQueue* next_queue = + next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get(); + DCHECK(next_queue && !next_queue->IsEmpty()); // Accept all non-shared tiles. - const Tile* tile = **next_iterator; + const Tile* tile = next_queue->Top(); if (!tile->is_shared()) break; @@ -256,51 +256,58 @@ if (next_tree == HigherPriorityTree(tree_priority, nullptr, nullptr, tile)) break; - ++(*next_iterator); + next_queue->Pop(); } } -WhichTree -RasterTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree( +WhichTree RasterTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree( TreePriority tree_priority) const { DCHECK(!IsEmpty()); - // If we only have one iterator with tiles, return it. - if (!active_iterator) + // If we only have one queue with tiles, return it. + if (!active_queue || active_queue->IsEmpty()) return PENDING_TREE; - if (!pending_iterator) + if (!pending_queue || pending_queue->IsEmpty()) return ACTIVE_TREE; // Now both iterators have tiles, so we have to decide based on tree priority. - return HigherPriorityTree( - tree_priority, &active_iterator, &pending_iterator, nullptr); + return HigherPriorityTree(tree_priority, active_queue.get(), + pending_queue.get(), nullptr); } scoped_refptr<base::debug::ConvertableToTraceFormat> -RasterTilePriorityQueue::PairedPictureLayerQueue::StateAsValue() const { +RasterTilePriorityQueue::PairedTilingSetQueue::StateAsValue() const { scoped_refptr<base::debug::TracedValue> state = new base::debug::TracedValue(); - state->BeginDictionary("active_iterator"); - TilePriority::PriorityBin active_priority_bin = - active_iterator ? (*active_iterator)->priority(ACTIVE_TREE).priority_bin - : TilePriority::EVENTUALLY; - TilePriority::PriorityBin pending_priority_bin = - active_iterator ? (*active_iterator)->priority(PENDING_TREE).priority_bin - : TilePriority::EVENTUALLY; - state->SetBoolean("has_tile", !!active_iterator); + + bool active_queue_has_tile = active_queue && !active_queue->IsEmpty(); + TilePriority::PriorityBin active_priority_bin = TilePriority::EVENTUALLY; + TilePriority::PriorityBin pending_priority_bin = TilePriority::EVENTUALLY; + if (active_queue_has_tile) { + active_priority_bin = + active_queue->Top()->priority(ACTIVE_TREE).priority_bin; + pending_priority_bin = + active_queue->Top()->priority(PENDING_TREE).priority_bin; + } + + state->BeginDictionary("active_queue"); + state->SetBoolean("has_tile", active_queue_has_tile); state->SetInteger("active_priority_bin", active_priority_bin); state->SetInteger("pending_priority_bin", pending_priority_bin); state->EndDictionary(); - state->BeginDictionary("pending_iterator"); - active_priority_bin = - pending_iterator ? (*pending_iterator)->priority(ACTIVE_TREE).priority_bin - : TilePriority::EVENTUALLY; - pending_priority_bin = - pending_iterator - ? (*pending_iterator)->priority(PENDING_TREE).priority_bin - : TilePriority::EVENTUALLY; - state->SetBoolean("has_tile", !!pending_iterator); + bool pending_queue_has_tile = pending_queue && !pending_queue->IsEmpty(); + active_priority_bin = TilePriority::EVENTUALLY; + pending_priority_bin = TilePriority::EVENTUALLY; + if (pending_queue_has_tile) { + active_priority_bin = + pending_queue->Top()->priority(ACTIVE_TREE).priority_bin; + pending_priority_bin = + pending_queue->Top()->priority(PENDING_TREE).priority_bin; + } + + state->BeginDictionary("pending_queue"); + state->SetBoolean("has_tile", active_queue_has_tile); state->SetInteger("active_priority_bin", active_priority_bin); state->SetInteger("pending_priority_bin", pending_priority_bin); state->EndDictionary();
diff --git a/cc/resources/raster_tile_priority_queue.h b/cc/resources/raster_tile_priority_queue.h index 3f04e97..416a57a 100644 --- a/cc/resources/raster_tile_priority_queue.h +++ b/cc/resources/raster_tile_priority_queue.h
@@ -12,16 +12,17 @@ #include "cc/base/cc_export.h" #include "cc/layers/picture_layer_impl.h" #include "cc/resources/tile_priority.h" +#include "cc/resources/tiling_set_raster_queue.h" namespace cc { class CC_EXPORT RasterTilePriorityQueue { public: - struct PairedPictureLayerQueue { - PairedPictureLayerQueue(); - PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair, - TreePriority tree_priority); - ~PairedPictureLayerQueue(); + struct PairedTilingSetQueue { + PairedTilingSetQueue(); + PairedTilingSetQueue(const PictureLayerImpl::Pair& layer_pair, + TreePriority tree_priority); + ~PairedTilingSetQueue(); bool IsEmpty() const; Tile* Top(TreePriority tree_priority); @@ -32,8 +33,8 @@ scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const; - PictureLayerImpl::LayerRasterTileIterator active_iterator; - PictureLayerImpl::LayerRasterTileIterator pending_iterator; + scoped_ptr<TilingSetRasterQueue> active_queue; + scoped_ptr<TilingSetRasterQueue> pending_queue; bool has_both_layers; // Set of returned tiles (excluding the current one) for DCHECKing. @@ -53,9 +54,9 @@ private: // TODO(vmpstr): This is potentially unnecessary if it becomes the case that - // PairedPictureLayerQueue is fast enough to copy. In that case, we can use - // objects directly (ie std::vector<PairedPictureLayerQueue>. - ScopedPtrVector<PairedPictureLayerQueue> paired_queues_; + // PairedTilingSetQueue is fast enough to copy. In that case, we can use + // objects directly (ie std::vector<PairedTilingSetQueue>. + ScopedPtrVector<PairedTilingSetQueue> paired_queues_; TreePriority tree_priority_; DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueue);
diff --git a/cc/resources/tiling_set_raster_queue.cc b/cc/resources/tiling_set_raster_queue.cc new file mode 100644 index 0000000..08f7642 --- /dev/null +++ b/cc/resources/tiling_set_raster_queue.cc
@@ -0,0 +1,117 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/resources/tiling_set_raster_queue.h" + +namespace cc { + +TilingSetRasterQueue::TilingSetRasterQueue() + : tiling_set_(nullptr), current_stage_(arraysize(stages_)) { +} + +TilingSetRasterQueue::TilingSetRasterQueue(PictureLayerTilingSet* tiling_set, + bool prioritize_low_res) + : tiling_set_(tiling_set), current_stage_(0) { + DCHECK(tiling_set_); + + // Early out if the tiling set has no tilings. + if (!tiling_set_->num_tilings()) { + current_stage_ = arraysize(stages_); + return; + } + + // Find high and low res tilings and initialize the iterators. + for (size_t i = 0; i < tiling_set_->num_tilings(); ++i) { + PictureLayerTiling* tiling = tiling_set_->tiling_at(i); + if (tiling->resolution() == HIGH_RESOLUTION) { + iterators_[HIGH_RES] = + PictureLayerTiling::TilingRasterTileIterator(tiling); + } + + if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) { + iterators_[LOW_RES] = + PictureLayerTiling::TilingRasterTileIterator(tiling); + } + } + + if (prioritize_low_res) { + stages_[0].iterator_type = LOW_RES; + stages_[0].tile_type = TilePriority::NOW; + + stages_[1].iterator_type = HIGH_RES; + stages_[1].tile_type = TilePriority::NOW; + } else { + stages_[0].iterator_type = HIGH_RES; + stages_[0].tile_type = TilePriority::NOW; + + stages_[1].iterator_type = LOW_RES; + stages_[1].tile_type = TilePriority::NOW; + } + + stages_[2].iterator_type = HIGH_RES; + stages_[2].tile_type = TilePriority::SOON; + + stages_[3].iterator_type = HIGH_RES; + stages_[3].tile_type = TilePriority::EVENTUALLY; + + IteratorType index = stages_[current_stage_].iterator_type; + TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; + if (!iterators_[index] || iterators_[index].get_type() != tile_type) + AdvanceToNextStage(); +} + +TilingSetRasterQueue::~TilingSetRasterQueue() { +} + +bool TilingSetRasterQueue::IsEmpty() const { + return current_stage_ >= arraysize(stages_); +} + +void TilingSetRasterQueue::Pop() { + IteratorType index = stages_[current_stage_].iterator_type; + TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; + + // First advance the iterator. + DCHECK(iterators_[index]); + DCHECK(iterators_[index].get_type() == tile_type); + ++iterators_[index]; + + if (!iterators_[index] || iterators_[index].get_type() != tile_type) + AdvanceToNextStage(); +} + +Tile* TilingSetRasterQueue::Top() { + DCHECK(!IsEmpty()); + + IteratorType index = stages_[current_stage_].iterator_type; + DCHECK(iterators_[index]); + DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type); + + return *iterators_[index]; +} + +const Tile* TilingSetRasterQueue::Top() const { + DCHECK(!IsEmpty()); + + IteratorType index = stages_[current_stage_].iterator_type; + DCHECK(iterators_[index]); + DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type); + + return *iterators_[index]; +} + +void TilingSetRasterQueue::AdvanceToNextStage() { + DCHECK_LT(current_stage_, arraysize(stages_)); + ++current_stage_; + while (current_stage_ < arraysize(stages_)) { + IteratorType index = stages_[current_stage_].iterator_type; + TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type; + + if (iterators_[index] && iterators_[index].get_type() == tile_type) + break; + ++current_stage_; + } +} + +} // namespace cc
diff --git a/cc/resources/tiling_set_raster_queue.h b/cc/resources/tiling_set_raster_queue.h new file mode 100644 index 0000000..58faa8a --- /dev/null +++ b/cc/resources/tiling_set_raster_queue.h
@@ -0,0 +1,46 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_ +#define CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_ + +#include "cc/base/cc_export.h" +#include "cc/resources/picture_layer_tiling_set.h" + +namespace cc { + +class CC_EXPORT TilingSetRasterQueue { + public: + TilingSetRasterQueue(); + TilingSetRasterQueue(PictureLayerTilingSet* tiling_set, + bool prioritize_low_res); + ~TilingSetRasterQueue(); + + Tile* Top(); + const Tile* Top() const; + void Pop(); + bool IsEmpty() const; + + private: + enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS }; + + void AdvanceToNextStage(); + + PictureLayerTilingSet* tiling_set_; + + struct IterationStage { + IteratorType iterator_type; + TilePriority::PriorityBin tile_type; + }; + + size_t current_stage_; + + // One low res stage, and three high res stages. + IterationStage stages_[4]; + PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS]; +}; + +} // namespace cc + +#endif // CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 0cce5dc..5a70ec6 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -543,9 +543,8 @@ advance_commit_state_task_.Cancel(); - base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); begin_impl_frame_args_ = args; - begin_impl_frame_args_.deadline -= draw_duration_estimate; + begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); if (!state_machine_.impl_latency_takes_priority() && main_thread_is_in_high_latency_mode && @@ -569,51 +568,43 @@ // up the BeginImplFrame and deadline as well. OnBeginImplFrameDeadline(); } else { - ScheduleBeginImplFrameDeadline( - AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); + ScheduleBeginImplFrameDeadline(); } } -base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( - const BeginFrameArgs& args, - base::TimeDelta draw_duration_estimate) const { +void Scheduler::ScheduleBeginImplFrameDeadline() { // The synchronous compositor does not post a deadline task. DCHECK(!settings_.using_synchronous_renderer_compositor); - if (settings_.main_thread_should_always_be_low_latency) { - // In main thread low latency mode, always start deadline early. - return base::TimeTicks(); - } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { - // We are ready to draw a new active tree immediately. - // We don't use Now() here because it's somewhat expensive to call. - return base::TimeTicks(); - } else if (settings_.main_thread_should_always_be_low_latency) { - // Post long deadline to keep advancing during idle period. After activation - // we will be able to trigger deadline early. - // TODO(weiliangc): Don't post deadline once input is deferred with - // BeginRetroFrames. - return args.frame_time + args.interval; - } else if (state_machine_.needs_redraw()) { - // We have an animation or fast input path on the impl thread that wants - // to draw, so don't wait too long for a new active tree. - return args.deadline - draw_duration_estimate; - } else { - // The impl thread doesn't have anything it wants to draw and we are just - // waiting for a new active tree, so post the deadline for the next - // expected BeginImplFrame start. This allows us to draw immediately when - // there is a new active tree, instead of waiting for the next - // BeginImplFrame. - // TODO(brianderson): Handle long deadlines (that are past the next frame's - // frame time) properly instead of using this hack. - return args.frame_time + args.interval; - } -} -void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { - TRACE_EVENT1( - "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); begin_impl_frame_deadline_task_.Cancel(); begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); + begin_impl_frame_deadline_mode_ = + state_machine_.CurrentBeginImplFrameDeadlineMode(); + + base::TimeTicks deadline; + switch (begin_impl_frame_deadline_mode_) { + case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: + // We are ready to draw a new active tree immediately. + // We don't use Now() here because it's somewhat expensive to call. + deadline = base::TimeTicks(); + break; + case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR: + // We are animating on the impl thread but we can wait for some time. + deadline = begin_impl_frame_args_.deadline; + break; + case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: + // We are blocked for one reason or another and we should wait. + // TODO(brianderson): Handle long deadlines (that are past the next + // frame's frame time) properly instead of using this hack. + deadline = + begin_impl_frame_args_.frame_time + begin_impl_frame_args_.interval; + break; + } + + TRACE_EVENT1( + "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); + base::TimeDelta delta = deadline - Now(); if (delta <= base::TimeDelta()) delta = base::TimeDelta(); @@ -621,6 +612,19 @@ FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); } +void Scheduler::RescheduleBeginImplFrameDeadlineIfNeeded() { + if (settings_.using_synchronous_renderer_compositor) + return; + + if (state_machine_.begin_impl_frame_state() != + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) + return; + + if (begin_impl_frame_deadline_mode_ != + state_machine_.CurrentBeginImplFrameDeadlineMode()) + ScheduleBeginImplFrameDeadline(); +} + void Scheduler::OnBeginImplFrameDeadline() { TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); begin_impl_frame_deadline_task_.Cancel(); @@ -716,10 +720,7 @@ SetupNextBeginFrameIfNeeded(); client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); - if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { - DCHECK(!settings_.using_synchronous_renderer_compositor); - ScheduleBeginImplFrameDeadline(base::TimeTicks()); - } + RescheduleBeginImplFrameDeadlineIfNeeded(); } bool Scheduler::WillDrawIfNeeded() const {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index ef52ccf..1175d73 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h
@@ -205,6 +205,8 @@ bool begin_retro_frame_posted_; std::deque<BeginFrameArgs> begin_retro_frame_args_; BeginFrameArgs begin_impl_frame_args_; + SchedulerStateMachine::BeginImplFrameDeadlineMode + begin_impl_frame_deadline_mode_; base::Closure begin_retro_frame_closure_; base::Closure begin_unthrottled_frame_closure_; @@ -221,10 +223,8 @@ SchedulerStateMachine::Action inside_action_; private: - base::TimeTicks AdjustedBeginImplFrameDeadline( - const BeginFrameArgs& args, - base::TimeDelta draw_duration_estimate) const; - void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline); + void ScheduleBeginImplFrameDeadline(); + void RescheduleBeginImplFrameDeadlineIfNeeded(); void SetupNextBeginFrameIfNeeded(); void PostBeginRetroFrameIfNeeded(); void SetupPollingMechanisms(bool needs_begin_frame);
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc index 53abe7b..6a5cbbc 100644 --- a/cc/scheduler/scheduler_settings.cc +++ b/cc/scheduler/scheduler_settings.cc
@@ -39,8 +39,7 @@ throttle_frame_production(settings.throttle_frame_production), disable_hi_res_timer_tasks_on_battery( settings.disable_hi_res_timer_tasks_on_battery), - main_thread_should_always_be_low_latency( - settings.main_thread_should_always_be_low_latency), + main_thread_should_always_be_low_latency(false), background_frame_interval(base::TimeDelta::FromSecondsD( 1.0 / settings.background_animation_rate)) { }
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 2946a2c..8e87c0f 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -820,7 +820,25 @@ begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE; } -bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const { +SchedulerStateMachine::BeginImplFrameDeadlineMode +SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { + if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { + return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; + } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { + // We have an animation or fast input path on the impl thread that wants + // to draw, so don't wait too long for a new active tree. + // If we are swap throttled we should wait until we are unblocked. + return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR; + } else { + // The impl thread doesn't have anything it wants to draw and we are just + // waiting for a new active tree or we are swap throttled. In short we are + // blocked. + return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE; + } +} + +bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() + const { // TODO(brianderson): This should take into account multiple commit sources. if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 12f8635..6e30694 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -62,6 +62,14 @@ }; static const char* BeginImplFrameStateToString(BeginImplFrameState state); + enum BeginImplFrameDeadlineMode { + BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE, + BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR, + BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE, + }; + static const char* BeginImplFrameDeadlineModeToString( + BeginImplFrameDeadlineMode mode); + enum CommitState { COMMIT_STATE_IDLE, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT, @@ -128,10 +136,10 @@ void OnBeginImplFrameDeadlinePending(); void OnBeginImplFrameDeadline(); void OnBeginImplFrameIdle(); - bool ShouldTriggerBeginImplFrameDeadlineEarly() const; BeginImplFrameState begin_impl_frame_state() const { return begin_impl_frame_state_; } + BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const; // If the main thread didn't manage to produce a new frame in time for the // impl thread to draw, it is in a high latency mode. @@ -258,6 +266,8 @@ bool BeginFrameNeededForChildren() const; bool ProactiveBeginFrameWanted() const; + bool ShouldTriggerBeginImplFrameDeadlineImmediately() const; + // True if we need to force activations to make forward progress. bool PendingActivationsShouldBeForced() const;
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index f46389b..7bbfa37 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -103,6 +103,8 @@ void SetHasPendingTree(bool has_pending_tree) { has_pending_tree_ = has_pending_tree; } + + using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately; }; TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { @@ -232,7 +234,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( @@ -1731,7 +1733,8 @@ EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); } -TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) { +TEST(SchedulerStateMachineTest, + TestTriggerDeadlineImmediatelyAfterAbortedCommit) { SchedulerSettings settings; settings.impl_side_painting = true; StateMachine state(settings); @@ -1762,7 +1765,7 @@ // Since the commit was aborted, we should draw right away instead of waiting // for the deadline. - EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); } void FinishPreviousCommitAndDrawWithoutExitingDeadline( @@ -1782,7 +1785,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); @@ -1811,9 +1814,9 @@ // Verify the deadline is not triggered early until we enter // prefer impl latency mode. - EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.SetImplLatencyTakesPriority(true); - EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); // Trigger the deadline. state.OnBeginImplFrameDeadline(); @@ -1842,12 +1845,13 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } -TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyOnLostOutputSurface) { +TEST(SchedulerStateMachineTest, + TestTriggerDeadlineImmediatelyOnLostOutputSurface) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); @@ -1862,12 +1866,12 @@ EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); state.DidLoseOutputSurface(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // The deadline should be triggered immediately when output surface is lost. - EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); + EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately()); } TEST(SchedulerStateMachineTest, TestSetNeedsAnimate) {
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 2992dbc..0997049 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -1319,6 +1319,7 @@ scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); + scheduler->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1)); InitializeOutputSurfaceAndFirstCommit(scheduler, &client); // To test swap ack throttling, this test disables automatic swap acks. @@ -1331,12 +1332,7 @@ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client); client.Reset(); - // Create a BeginFrame with a long deadline to avoid race conditions. - // This is the first BeginFrame, which will be handled immediately. - BeginFrameArgs args = - CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); - args.deadline += base::TimeDelta::FromHours(1); - client.fake_external_begin_frame_source()->TestOnBeginFrame(args); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1344,11 +1340,10 @@ client.Reset(); // Queue BeginFrame while we are still handling the previous BeginFrame. - EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - args.frame_time += base::TimeDelta::FromSeconds(1); - client.fake_external_begin_frame_source()->TestOnBeginFrame(args); + client.SendNextBeginFrame(); EXPECT_NO_ACTION(client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_TRUE(client.needs_begin_frames()); client.Reset(); // NotifyReadyToCommit should trigger the pending commit and draw. @@ -1359,7 +1354,8 @@ client.Reset(); // Swapping will put us into a swap throttled state. - client.task_runner().RunPendingTasks(); // Run posted deadline. + // Run posted deadline. + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); @@ -1369,35 +1365,32 @@ // While swap throttled, BeginRetroFrames should trigger BeginImplFrames // but not a BeginMainFrame or draw. scheduler->SetNeedsCommit(); - client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. - EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); + scheduler->SetNeedsRedraw(); + // Run posted BeginRetroFrame. + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(false)); + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client.needs_begin_frames()); client.Reset(); - // Queue BeginFrame while we are still handling the previous BeginFrame. - args.frame_time += base::TimeDelta::FromSeconds(1); - client.fake_external_begin_frame_source()->TestOnBeginFrame(args); - EXPECT_NO_ACTION(client); + // Let time pass sufficiently beyond the regular deadline but not beyond the + // late deadline. + client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() - + base::TimeDelta::FromMicroseconds(1)); + client.task_runner().RunUntilTime(client.now_src()->Now()); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_frames()); - client.Reset(); // Take us out of a swap throttled state. scheduler->DidSwapBuffersComplete(); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); + EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client.needs_begin_frames()); client.Reset(); - // BeginImplFrame deadline should draw. - scheduler->SetNeedsRedraw(); - - EXPECT_TRUE(client.task_runner().RunTasksWhile( - client.ImplFrameDeadlinePending(true))); - - EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); + // Verify that the deadline was rescheduled. + client.task_runner().RunUntilTime(client.now_src()->Now()); + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); EXPECT_TRUE(client.needs_begin_frames()); client.Reset(); @@ -1630,6 +1623,7 @@ scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); + scheduler->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1)); InitializeOutputSurfaceAndFirstCommit(scheduler, &client); DCHECK(!client.fake_external_begin_frame_source()); @@ -1645,7 +1639,7 @@ client.Reset(); // Trigger the first BeginImplFrame and BeginMainFrame - client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1658,7 +1652,8 @@ client.Reset(); // Swapping will put us into a swap throttled state. - client.task_runner().RunPendingTasks(); // Run posted deadline. + // Run posted deadline. + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); @@ -1667,22 +1662,33 @@ // While swap throttled, BeginFrames should trigger BeginImplFrames, // but not a BeginMainFrame or draw. scheduler->SetNeedsCommit(); - client.task_runner().RunPendingTasks(); // Run posted BeginFrame. - EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); + scheduler->SetNeedsRedraw(); + client.AdvanceFrame(); // Run posted BeginFrame. + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); + // Let time pass sufficiently beyond the regular deadline but not beyond the + // late deadline. + client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() - + base::TimeDelta::FromMicroseconds(1)); + client.task_runner().RunUntilTime(client.now_src()->Now()); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + // Take us out of a swap throttled state. scheduler->DidSwapBuffersComplete(); - EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); + EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); - // BeginImplFrame deadline should draw. - scheduler->SetNeedsRedraw(); - client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); + // Verify that the deadline was rescheduled. + // We can't use RunUntilTime(now) here because the next frame is also + // scheduled if throttle_frame_production = false. + base::TimeTicks before_deadline = client.now_src()->Now(); + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); + base::TimeTicks after_deadline = client.now_src()->Now(); + EXPECT_EQ(after_deadline, before_deadline); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); }
diff --git a/cc/test/geometry_test_utils.h b/cc/test/geometry_test_utils.h index b743f58..38112a8 100644 --- a/cc/test/geometry_test_utils.h +++ b/cc/test/geometry_test_utils.h
@@ -29,33 +29,6 @@ EXPECT_NEAR((expected).height(), (actual).height(), (abs_error)); \ } while (false) -#define EXPECT_RECT_EQ(expected, actual) \ -do { \ - EXPECT_EQ((expected).x(), (actual).x()); \ - EXPECT_EQ((expected).y(), (actual).y()); \ - EXPECT_EQ((expected).width(), (actual).width()); \ - EXPECT_EQ((expected).height(), (actual).height()); \ -} while (false) - -#define EXPECT_SIZE_EQ(expected, actual) \ -do { \ - EXPECT_EQ((expected).width(), (actual).width()); \ - EXPECT_EQ((expected).height(), (actual).height()); \ -} while (false) - -#define EXPECT_POINT_EQ(expected, actual) \ -do { \ - EXPECT_EQ((expected).x(), (actual).x()); \ - EXPECT_EQ((expected).y(), (actual).y()); \ -} while (false) - -#define EXPECT_POINT3F_EQ(expected, actual) \ -do { \ - EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \ - EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \ - EXPECT_FLOAT_EQ((expected).z(), (actual).z()); \ -} while (false) - #define EXPECT_VECTOR_EQ(expected, actual) \ do { \ EXPECT_EQ((expected).x(), (actual).x()); \
diff --git a/cc/test/layer_tree_json_parser_unittest.cc b/cc/test/layer_tree_json_parser_unittest.cc index 4f9c562..a11d545 100644 --- a/cc/test/layer_tree_json_parser_unittest.cc +++ b/cc/test/layer_tree_json_parser_unittest.cc
@@ -27,10 +27,9 @@ RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->children().size(), layer->children().size())); - RETURN_IF_EXPECTATION_FAILS(EXPECT_SIZE_EQ(layer_impl->bounds(), - layer->bounds())); - RETURN_IF_EXPECTATION_FAILS(EXPECT_POINT_EQ(layer_impl->position(), - layer->position())); + RETURN_IF_EXPECTATION_FAILS(EXPECT_EQ(layer_impl->bounds(), layer->bounds())); + RETURN_IF_EXPECTATION_FAILS( + EXPECT_EQ(layer_impl->position(), layer->position())); RETURN_IF_EXPECTATION_FAILS( EXPECT_TRANSFORMATION_MATRIX_EQ(layer_impl->draw_transform(), layer->draw_transform()));
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 9f08677..5be1240 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -785,11 +785,6 @@ RunTest(true, false, true); } -void LayerTreeTest::RunTestWithMainThreadLowLatency() { - settings_.main_thread_should_always_be_low_latency = true; - RunTest(false, false, false); -} - void LayerTreeTest::RequestNewOutputSurface(bool fallback) { layer_tree_host_->SetOutputSurface(CreateOutputSurface(fallback)); }
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index ba2ef69..863100b 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h
@@ -176,7 +176,6 @@ bool delegating_renderer, bool impl_side_painting); virtual void RunTestWithImplSidePainting(); - virtual void RunTestWithMainThreadLowLatency(); bool HasImplThread() { return proxy() ? proxy()->HasImplThread() : false; } base::SingleThreadTaskRunner* ImplThreadTaskRunner() { @@ -237,18 +236,7 @@ } // namespace cc -#define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \ - TEST_FIXTURE_NAME) \ - TEST_F( \ - TEST_FIXTURE_NAME, \ - RunSingleThread_DirectRenderer_MainThreadPaint_MainThreadLowLatency) { \ - RunTestWithMainThreadLowLatency(); \ - } \ - class SingleThreadDirectNoImplLowLatencyNeedsSemicolon##TEST_FIXTURE_NAME {} - #define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \ - SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \ - TEST_FIXTURE_NAME); \ TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_MainThreadPaint) { \ RunTest(false, false, false); \ } \
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 361fae1..22b1196 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -363,6 +363,9 @@ sync_tree->PushPageScaleFromMainThread( page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_); + sync_tree->elastic_overscroll()->PushFromMainThread(elastic_overscroll_); + if (sync_tree->IsActiveTree()) + sync_tree->elastic_overscroll()->PushPendingToActive(); sync_tree->PassSwapPromises(&swap_promise_list_); @@ -875,6 +878,7 @@ LayerTreeHostCommon::CalcDrawPropsMainInputs inputs( root_layer, device_viewport_size(), gfx::Transform(), device_scale_factor_, page_scale_factor_, page_scale_layer, + elastic_overscroll_, overscroll_elasticity_layer_.get(), GetRendererCapabilities().max_texture_size, settings_.can_use_lcd_text, settings_.layers_always_allowed_lcd_text, can_render_to_separate_surface, @@ -1126,9 +1130,8 @@ } if (!inner_viewport_scroll_delta.IsZero() || - !outer_viewport_scroll_delta.IsZero() || - info->page_scale_delta != 1.f || - info->top_controls_delta) { + !outer_viewport_scroll_delta.IsZero() || info->page_scale_delta != 1.f || + !info->elastic_overscroll_delta.IsZero() || info->top_controls_delta) { // Preemptively apply the scroll offset and scale delta here before sending // it to the client. If the client comes back and sets it to the same // value, then the layer can early out without needing a full commit. @@ -1147,12 +1150,15 @@ } ApplyPageScaleDeltaFromImplSide(info->page_scale_delta); + elastic_overscroll_ += info->elastic_overscroll_delta; if (!settings_.use_pinch_virtual_viewport) { client_->ApplyViewportDeltas( inner_viewport_scroll_delta + outer_viewport_scroll_delta, info->page_scale_delta, info->top_controls_delta); } else { + // TODO(ccameron): pass the elastic overscroll here so that input events + // may be translated appropriately. client_->ApplyViewportDeltas( inner_viewport_scroll_delta, outer_viewport_scroll_delta,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 9d758c8..75165ad 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -223,6 +223,7 @@ float min_page_scale_factor, float max_page_scale_factor); float page_scale_factor() const { return page_scale_factor_; } + gfx::Vector2dF elastic_overscroll() const { return elastic_overscroll_; } SkColor background_color() const { return background_color_; } void set_background_color(SkColor color) { background_color_ = color; } @@ -428,6 +429,7 @@ float page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; + gfx::Vector2dF elastic_overscroll_; bool has_gpu_rasterization_trigger_; bool content_is_suitable_for_gpu_rasterization_; bool gpu_rasterization_histogram_recorded_;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index 6d75687..9a9650f 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -17,6 +17,7 @@ #include "cc/trees/layer_sorter.h" #include "cc/trees/layer_tree_impl.h" #include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/transform.h" namespace cc { @@ -1267,6 +1268,8 @@ float device_scale_factor; float page_scale_factor; const LayerType* page_scale_application_layer; + gfx::Vector2dF elastic_overscroll; + const LayerType* elastic_overscroll_application_layer; bool can_adjust_raster_scales; bool can_render_to_separate_surface; bool layers_always_allowed_lcd_text; @@ -1418,6 +1421,14 @@ return layer_list; } +static inline gfx::Vector2d BoundsDelta(Layer* layer) { + return gfx::Vector2d(); +} + +static inline gfx::Vector2d BoundsDelta(LayerImpl* layer) { + return gfx::ToCeiledVector2d(layer->bounds_delta()); +} + template <typename LayerType, typename GetIndexAndCountType> static void SortLayerListContributions( const LayerType& parent, @@ -1806,8 +1817,6 @@ layer->contents_opaque(); } - gfx::Rect content_rect(layer->content_bounds()); - // full_hierarchy_matrix is the matrix that transforms objects between screen // space (except projection matrix) and the most recent RenderSurfaceImpl's // space. next_hierarchy_matrix will only change if this layer uses a new @@ -2044,8 +2053,22 @@ if (adjust_text_aa) layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text; - gfx::Rect rect_in_target_space = - MathUtil::MapEnclosingClippedRect(layer->draw_transform(), content_rect); + gfx::Size content_size_affected_by_delta(layer->content_bounds()); + + // Non-zero BoundsDelta imply the contents_scale of 1.0 + // because BoundsDela is only set on Android where + // ContentScalingLayer is never used. + DCHECK_IMPLIES(!BoundsDelta(layer).IsZero(), + (layer->contents_scale_x() == 1.0 && + layer->contents_scale_y() == 1.0)); + + // Thus we can omit contents scale in the following calculation. + gfx::Vector2d bounds_delta = BoundsDelta(layer); + content_size_affected_by_delta.Enlarge(bounds_delta.x(), bounds_delta.y()); + + gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect( + layer->draw_transform(), + gfx::Rect(content_size_affected_by_delta)); if (LayerClipsSubtree(layer)) { layer_or_ancestor_clips_descendants = true; @@ -2100,6 +2123,10 @@ globals.page_scale_factor); data_for_children.in_subtree_of_page_scale_application_layer = true; } + if (layer == globals.elastic_overscroll_application_layer) { + data_for_children.parent_matrix.Translate(globals.elastic_overscroll.x(), + globals.elastic_overscroll.y()); + } // Flatten to 2D if the layer doesn't preserve 3D. if (layer->should_flatten_transform()) @@ -2378,6 +2405,9 @@ inputs.device_scale_factor * device_transform_scale; globals->page_scale_factor = inputs.page_scale_factor; globals->page_scale_application_layer = inputs.page_scale_application_layer; + globals->elastic_overscroll = inputs.elastic_overscroll; + globals->elastic_overscroll_application_layer = + inputs.elastic_overscroll_application_layer; globals->can_render_to_separate_surface = inputs.can_render_to_separate_surface; globals->can_adjust_raster_scales = inputs.can_adjust_raster_scales;
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h index 349b341..81aca55 100644 --- a/cc/trees/layer_tree_host_common.h +++ b/cc/trees/layer_tree_host_common.h
@@ -38,6 +38,8 @@ float device_scale_factor, float page_scale_factor, const LayerType* page_scale_application_layer, + const gfx::Vector2dF& elastic_overscroll, + const LayerType* elastic_overscroll_application_layer, int max_texture_size, bool can_use_lcd_text, bool layers_always_allowed_lcd_text, @@ -51,6 +53,9 @@ device_scale_factor(device_scale_factor), page_scale_factor(page_scale_factor), page_scale_application_layer(page_scale_application_layer), + elastic_overscroll(elastic_overscroll), + elastic_overscroll_application_layer( + elastic_overscroll_application_layer), max_texture_size(max_texture_size), can_use_lcd_text(can_use_lcd_text), layers_always_allowed_lcd_text(layers_always_allowed_lcd_text), @@ -66,6 +71,8 @@ float device_scale_factor; float page_scale_factor; const LayerType* page_scale_application_layer; + gfx::Vector2dF elastic_overscroll; + const LayerType* elastic_overscroll_application_layer; int max_texture_size; bool can_use_lcd_text; bool layers_always_allowed_lcd_text; @@ -145,6 +152,7 @@ std::vector<LayerTreeHostCommon::ScrollUpdateInfo> scrolls; float page_scale_delta; + gfx::Vector2dF elastic_overscroll_delta; float top_controls_delta; ScopedPtrVector<SwapPromise> swap_promises; }; @@ -223,6 +231,8 @@ 1.f, 1.f, NULL, + gfx::Vector2dF(), + NULL, std::numeric_limits<int>::max() / 2, false, false, @@ -248,6 +258,8 @@ 1.f, 1.f, NULL, + gfx::Vector2dF(), + NULL, std::numeric_limits<int>::max() / 2, false, false,
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc index 2fd2146..ab72cf9 100644 --- a/cc/trees/layer_tree_host_common_perftest.cc +++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -96,6 +96,8 @@ layer_tree_host()->device_viewport_size(), gfx::Transform(), layer_tree_host()->device_scale_factor(), layer_tree_host()->page_scale_factor(), + layer_tree_host()->overscroll_elasticity_layer(), + layer_tree_host()->elastic_overscroll(), layer_tree_host()->page_scale_layer(), max_texture_size, layer_tree_host()->settings().can_use_lcd_text, layer_tree_host()->settings().layers_always_allowed_lcd_text, @@ -148,7 +150,9 @@ active_tree->root_layer(), active_tree->DrawViewportSize(), host_impl->DrawTransform(), active_tree->device_scale_factor(), active_tree->current_page_scale_factor(), - active_tree->InnerViewportContainerLayer(), max_texture_size, + active_tree->InnerViewportContainerLayer(), + active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()), + active_tree->overscroll_elasticity_layer(), max_texture_size, host_impl->settings().can_use_lcd_text, host_impl->settings().layers_always_allowed_lcd_text, can_render_to_separate_surface,
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index 8c02bd3..f8e5be9 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -1943,12 +1943,9 @@ inputs.can_adjust_raster_scales = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); - EXPECT_RECT_EQ(gfx::Rect(5, 5, 10, 10), - grand_child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5), - grand_child3->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5), - grand_child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(5, 5, 10, 10), grand_child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect()); EXPECT_TRUE(grand_child4->drawable_content_rect().IsEmpty()); } @@ -2090,12 +2087,12 @@ // Surfaces are clipped by their parent, but un-affected by the owning layer's // masksToBounds. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20), - grand_child1->render_surface()->clip_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20), - grand_child2->render_surface()->clip_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20), - grand_child3->render_surface()->clip_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 20, 20), + grand_child1->render_surface()->clip_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 20, 20), + grand_child2->render_surface()->clip_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 20, 20), + grand_child3->render_surface()->clip_rect()); } TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) { @@ -2320,7 +2317,7 @@ gfx::Rect expected = gfx::Rect(10, 10, 30, 30); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 2: Layer is outside the surface rect. layer_content_rect = gfx::Rect(120, 120, 30, 30); @@ -2333,7 +2330,7 @@ expected = gfx::Rect(80, 80, 20, 20); actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) { @@ -2350,7 +2347,7 @@ gfx::Rect expected = gfx::Rect(0, 0, 30, 30); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 2: Layer is outside the surface rect. layer_to_surface_transform.MakeIdentity(); @@ -2365,7 +2362,7 @@ expected = gfx::Rect(0, 0, 20, 20); actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) { @@ -2384,7 +2381,7 @@ gfx::Rect expected = gfx::Rect(0, 0, 30, 30); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 2: Layer is outside the surface rect. layer_to_surface_transform.MakeIdentity(); @@ -2404,7 +2401,7 @@ expected = gfx::Rect(0, 0, 30, 30); actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 4: The layer is rotated about its top-left corner, and translated // upwards. In surface space, the layer is oriented diagonally, with only the @@ -2417,7 +2414,7 @@ expected = gfx::Rect(15, 0, 15, 30); // Right half of layer bounds. actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) { @@ -2435,7 +2432,7 @@ gfx::Rect expected = gfx::Rect(0, 0, 100, 100); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 2: Orthographic projection of a layer rotated about y-axis by 45 // degrees, but shifted to the side so only the right-half the layer would be @@ -2450,7 +2447,7 @@ expected = gfx::Rect(50, 0, 50, 100); // Tight half of the layer. actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) { @@ -2478,7 +2475,7 @@ gfx::Rect expected = gfx::Rect(-50, -50, 200, 200); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); // Case 2: same projection as before, except that the layer is also translated // to the side, so that only the right half of the layer should be visible. @@ -2495,7 +2492,7 @@ // bounding rect. actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, @@ -2519,7 +2516,7 @@ gfx::Rect expected = gfx::Rect(0, 0, 100, 100); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveWhenClippedByW) { @@ -2592,7 +2589,7 @@ gfx::Rect expected = gfx::Rect(-10, -10, 20, 20); gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_content_rect, layer_to_surface_transform); - EXPECT_RECT_EQ(expected, actual); + EXPECT_EQ(expected, actual); } TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) { @@ -2642,22 +2639,22 @@ ExecuteCalculateDrawProperties(root.get()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible_content_rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); // layer visible_content_rects are clipped by their target surface. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect()); EXPECT_TRUE(child3->visible_content_rect().IsEmpty()); // layer drawable_content_rects are not clipped. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -2720,24 +2717,22 @@ ASSERT_FALSE(child->render_surface()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect()); // All grandchild visible content rects should be clipped by child. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect()); EXPECT_TRUE(grand_child3->visible_content_rect().IsEmpty()); // All grandchild DrawableContentRects should also be clipped by child. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), - grand_child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(75, 75, 25, 25), - grand_child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(5, 5, 50, 50), grand_child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 25, 25), grand_child2->drawable_content_rect()); EXPECT_TRUE(grand_child3->drawable_content_rect().IsEmpty()); } @@ -2801,28 +2796,27 @@ ASSERT_TRUE(render_surface1->render_surface()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), - render_surface1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect()); // An unclipped surface grows its DrawableContentRect to include all drawable // regions of the subtree. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(5, 5, 170, 170), + render_surface1->render_surface()->DrawableContentRect()); // All layers that draw content into the unclipped surface are also unclipped. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -3085,30 +3079,29 @@ ASSERT_TRUE(render_surface1->render_surface()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), - render_surface1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect()); // A clipped surface grows its DrawableContentRect to include all drawable // regions of the subtree, but also gets clamped by the ancestor's clip. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(5, 5, 95, 95), + render_surface1->render_surface()->DrawableContentRect()); // All layers that draw content into the surface have their visible content // rect clipped by the surface clip rect. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect()); EXPECT_TRUE(child3->visible_content_rect().IsEmpty()); // But the DrawableContentRects are unclipped. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -3184,37 +3177,35 @@ ASSERT_TRUE(render_surface1->render_surface()); ASSERT_TRUE(render_surface2->render_surface()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), - render_surface1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), - render_surface2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface2->visible_content_rect()); // A clipped surface grows its DrawableContentRect to include all drawable // regions of the subtree, but also gets clamped by the ancestor's clip. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(5, 5, 95, 95), + render_surface1->render_surface()->DrawableContentRect()); // render_surface1 lives in the "unclipped universe" of render_surface1, and // is only implicitly clipped by render_surface1's content rect. So, // render_surface2 grows to enclose all drawable content of its subtree. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170), - render_surface2->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(5, 5, 170, 170), + render_surface2->render_surface()->DrawableContentRect()); // All layers that draw content into render_surface2 think they are unclipped. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); // DrawableContentRects are also unclipped. - EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -3262,14 +3253,13 @@ ASSERT_TRUE(render_surface1->render_surface()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), - render_surface1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect()); // The unclipped surface grows its DrawableContentRect to include all drawable // regions of the subtree. @@ -3279,13 +3269,12 @@ 50 - diagonal_radius, diagonal_radius * 2, diagonal_radius * 2); - EXPECT_RECT_EQ(expected_surface_drawable_content, - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(expected_surface_drawable_content, + render_surface1->render_surface()->DrawableContentRect()); // All layers that draw content into the unclipped surface are also unclipped. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(expected_surface_drawable_content, - child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(expected_surface_drawable_content, child1->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, @@ -3344,18 +3333,18 @@ diagonal_radius * 2); gfx::Rect expected_surface_drawable_content = gfx::IntersectRects(unclipped_surface_content, gfx::Rect(0, 0, 50, 50)); - EXPECT_RECT_EQ(expected_surface_drawable_content, - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(expected_surface_drawable_content, + render_surface1->render_surface()->DrawableContentRect()); // On the clipped surface, only a quarter of the child1 is visible, but when // rotating it back to child1's content space, the actual enclosing rect ends // up covering the full left half of child1. // // Given the floating point math, this number is a little bit fuzzy. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect()); // The child's DrawableContentRect is unclipped. - EXPECT_RECT_EQ(unclipped_surface_content, child1->drawable_content_rect()); + EXPECT_EQ(unclipped_surface_content, child1->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) { @@ -3434,35 +3423,31 @@ // drawable_content_rects for all layers and surfaces are scaled by // device_scale_factor. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200), - root->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(10, 10, 190, 190), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 200, 200), + root->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(10, 10, 190, 190), + render_surface1->render_surface()->DrawableContentRect()); // render_surface2 lives in the "unclipped universe" of render_surface1, and // is only implicitly clipped by render_surface1. - EXPECT_RECT_EQ(gfx::Rect(10, 10, 350, 350), - render_surface2->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::Rect(10, 10, 350, 350), + render_surface2->render_surface()->DrawableContentRect()); - EXPECT_RECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(150, 150, 100, 100), - child2->drawable_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(250, 250, 100, 100), - child3->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(150, 150, 100, 100), child2->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(250, 250, 100, 100), child3->drawable_content_rect()); // The root layer does not actually draw content of its own. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect()); // All layer visible content rects are not expressed in content space of each // layer, so they are not scaled by the device_scale_factor. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 3, 4), - render_surface1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 7, 13), - render_surface2->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); - EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 3, 4), render_surface1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 7, 13), render_surface2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect()); } TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) { @@ -5458,8 +5443,8 @@ EXPECT_TRANSFORMATION_MATRIX_EQ( child->screen_space_transform(), duplicate_child_non_owner->screen_space_transform()); - EXPECT_RECT_EQ(child->drawable_content_rect(), - duplicate_child_non_owner->drawable_content_rect()); + EXPECT_EQ(child->drawable_content_rect(), + duplicate_child_non_owner->drawable_content_rect()); EXPECT_EQ(child->content_bounds(), duplicate_child_non_owner->content_bounds()); @@ -8676,5 +8661,68 @@ EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_content_rect()); } +TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) { + FakeImplProxy proxy; + TestSharedBitmapManager shared_bitmap_manager; + FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager); + + // Set two layers: the root layer clips it's child, + // the child draws its content. + + gfx::Size root_size = gfx::Size(300, 500); + + // Sublayer should be bigger than the root enlarged by bounds_delta. + gfx::Size sublayer_size = gfx::Size(300, 1000); + + // Device viewport accomidated the root and the top controls. + gfx::Size device_viewport_size = gfx::Size(300, 600); + gfx::Transform identity_matrix; + + host_impl.active_tree()->SetRootLayer( + LayerImpl::Create(host_impl.active_tree(), 1)); + + LayerImpl* root = host_impl.active_tree()->root_layer(); + SetLayerPropertiesForTesting(root, + identity_matrix, + gfx::Point3F(), + gfx::PointF(), + root_size, + false, + false); + + root->SetContentBounds(root_size); + root->SetMasksToBounds(true); + + root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2)); + + LayerImpl* sublayer = root->child_at(0); + SetLayerPropertiesForTesting(sublayer, + identity_matrix, + gfx::Point3F(), + gfx::PointF(), + sublayer_size, + false, + false); + + sublayer->SetContentBounds(sublayer_size); + sublayer->SetDrawsContent(true); + + LayerImplList layer_impl_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, device_viewport_size, &layer_impl_list); + + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_content_rect()); + + root->SetBoundsDelta(gfx::Vector2dF(0.0, 50.0)); + + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + gfx::Rect affected_by_delta(0, 0, root_size.width(), + root_size.height() + 50); + EXPECT_EQ(affected_by_delta, sublayer->visible_content_rect()); +} + } // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 566fb57..e19c9a2 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -237,7 +237,8 @@ SetDebugState(settings.initial_debug_state); // LTHI always has an active tree. - active_tree_ = LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>()); + active_tree_ = LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>(), + new SyncedElasticOverscroll); TRACE_EVENT_OBJECT_CREATED_WITH_ID( TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_); @@ -1101,8 +1102,8 @@ void LayerTreeHostImpl::ResetTreesForTesting() { if (active_tree_) active_tree_->DetachLayerTree(); - active_tree_ = - LayerTreeImpl::create(this, active_tree()->page_scale_factor()); + active_tree_ = LayerTreeImpl::create(this, active_tree()->page_scale_factor(), + active_tree()->elastic_overscroll()); if (pending_tree_) pending_tree_->DetachLayerTree(); pending_tree_ = nullptr; @@ -1748,7 +1749,8 @@ recycle_tree_.swap(pending_tree_); else pending_tree_ = - LayerTreeImpl::create(this, active_tree()->page_scale_factor()); + LayerTreeImpl::create(this, active_tree()->page_scale_factor(), + active_tree()->elastic_overscroll()); // Update the delta from the active tree, which may have // adjusted its delta prior to the pending tree being created. @@ -2008,16 +2010,13 @@ } if (GetRendererCapabilities().using_image) { - unsigned image_target = GL_TEXTURE_2D; -#if defined(OS_MACOSX) - // GL_TEXTURE_RECTANGLE_ARB target is required by IOSurface backed images. - DCHECK(context_provider->ContextCapabilities().gpu.texture_rectangle); - image_target = GL_TEXTURE_RECTANGLE_ARB; -#endif - if (settings_.use_image_external) { - DCHECK(context_provider->ContextCapabilities().gpu.egl_image_external); - image_target = GL_TEXTURE_EXTERNAL_OES; - } + unsigned image_target = settings_.use_image_texture_target; + DCHECK_IMPLIES( + image_target == GL_TEXTURE_RECTANGLE_ARB, + context_provider->ContextCapabilities().gpu.texture_rectangle); + DCHECK_IMPLIES( + image_target == GL_TEXTURE_EXTERNAL_OES, + context_provider->ContextCapabilities().gpu.egl_image_external); if (settings_.use_zero_copy || IsSynchronousSingleThreaded()) { *resource_pool = @@ -2681,10 +2680,16 @@ } did_lock_scrolling_layer_ = true; - if (!allow_bubbling_for_current_layer) { + + // When scrolls are allowed to bubble, it's important that the original + // scrolling layer be preserved. This ensures that, after a scroll bubbles, + // the user can reverse scroll directions and immediately resume scrolling + // the original layer that scrolled. + if (!should_bubble_scrolls_) active_tree_->SetCurrentlyScrollingLayer(layer_impl); + + if (!allow_bubbling_for_current_layer) break; - } if (allow_unrestricted_bubbling_for_current_layer) { pending_delta -= applied_delta; @@ -3022,6 +3027,8 @@ CollectScrollDeltas(scroll_info.get(), active_tree_->root_layer()); scroll_info->page_scale_delta = active_tree_->page_scale_factor()->PullDeltaForMainThread(); + scroll_info->elastic_overscroll_delta = + active_tree_->elastic_overscroll()->PullDeltaForMainThread(); scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_); scroll_info->top_controls_delta = active_tree()->top_controls_delta(); active_tree_->set_sent_top_controls_delta(scroll_info->top_controls_delta);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 934946b..3ef9445 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5373,7 +5373,7 @@ // Verify the damage rect for the root render pass. const RenderPass* root_render_pass = frame.render_passes.back(); - EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect); + EXPECT_EQ(expected_damage, root_render_pass->damage_rect); // Verify the root and child layers' quads are generated and not being // culled. @@ -5381,13 +5381,13 @@ LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; gfx::RectF expected_child_visible_rect(child->content_bounds()); - EXPECT_RECT_EQ(expected_child_visible_rect, - root_render_pass->quad_list.front()->visible_rect); + EXPECT_EQ(expected_child_visible_rect, + root_render_pass->quad_list.front()->visible_rect); LayerImpl* root = host_impl_->active_tree()->root_layer(); gfx::RectF expected_root_visible_rect(root->content_bounds()); - EXPECT_RECT_EQ(expected_root_visible_rect, - root_render_pass->quad_list.ElementAt(1)->visible_rect); + EXPECT_EQ(expected_root_visible_rect, + root_render_pass->quad_list.ElementAt(1)->visible_rect); } host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); @@ -7621,6 +7621,56 @@ } } +TEST_F(LayerTreeHostImplVirtualViewportTest, + TouchFlingCanLockToViewportLayerAfterBubbling) { + gfx::Size content_size = gfx::Size(100, 160); + gfx::Size outer_viewport = gfx::Size(50, 80); + gfx::Size inner_viewport = gfx::Size(25, 40); + + SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport); + + LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer(); + + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(10, outer_viewport, outer_scroll); + LayerImpl* child_scroll = child.get(); + outer_scroll->children()[0]->AddChild(child.Pass()); + + DrawFrame(); + { + scoped_ptr<ScrollAndScaleSet> scroll_info; + + gfx::Vector2d scroll_delta(0, inner_viewport.height()); + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + + // The child should have scrolled up to its limit. + scroll_info = host_impl_->ProcessScrollDeltas(); + ASSERT_EQ(1u, scroll_info->scrolls.size()); + ExpectContains(*scroll_info, child_scroll->id(), scroll_delta); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); + + // The first |ScrollBy| after the fling should re-lock the scrolling + // layer to the first layer that scrolled, the inner viewport scroll layer. + EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin()); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); + + // The inner viewport should have scrolled up to its limit. + scroll_info = host_impl_->ProcessScrollDeltas(); + ASSERT_EQ(2u, scroll_info->scrolls.size()); + ExpectContains(*scroll_info, child_scroll->id(), scroll_delta); + ExpectContains(*scroll_info, inner_scroll->id(), scroll_delta); + + // As the locked layer is at its limit, no further scrolling can occur. + EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); + host_impl_->ScrollEnd(); + } +} + class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest { public: void SetUp() override {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index c029c78..d70d832 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -442,7 +442,7 @@ if (!num_draws_) { // If this is the first frame, expect full frame damage. - EXPECT_RECT_EQ(root_damage_rect, gfx::Rect(bounds_)); + EXPECT_EQ(root_damage_rect, gfx::Rect(bounds_)); } else { // Check that invalid_rect_ is indeed repainted. EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_)); @@ -624,17 +624,17 @@ switch (num_draws_) { case 0: - EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect); + EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect); break; case 1: case 2: - EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect); break; case 3: - EXPECT_RECT_EQ(invalid_rect_, root_damage_rect); + EXPECT_EQ(invalid_rect_, root_damage_rect); break; case 4: - EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect); + EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect); break; default: NOTREACHED(); @@ -736,12 +736,12 @@ // box. switch (host_impl->active_tree()->source_frame_number()) { case 0: - EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect); + EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect); break; case 1: case 2: case 3: - EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect); + EXPECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect); break; default: NOTREACHED(); @@ -1269,8 +1269,7 @@ ASSERT_EQ(2u, root->render_surface()->layer_list().size()); // The root render surface is the size of the viewport. - EXPECT_RECT_EQ(gfx::Rect(0, 0, 60, 60), - root->render_surface()->content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 60, 60), root->render_surface()->content_rect()); // The max tiling scale of the child should be scaled. EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale()); @@ -2643,10 +2642,10 @@ num_commits_++; if (num_commits_ == 1) { LayerImpl* root_layer = host_impl->active_tree()->root_layer(); - EXPECT_SIZE_EQ(gfx::Size(1, 1), root_layer->bounds()); + EXPECT_EQ(gfx::Size(1, 1), root_layer->bounds()); } else { LayerImpl* root_layer = host_impl->active_tree()->root_layer(); - EXPECT_SIZE_EQ(gfx::Size(2, 2), root_layer->bounds()); + EXPECT_EQ(gfx::Size(2, 2), root_layer->bounds()); EndTest(); } } @@ -2769,7 +2768,7 @@ CHECK_EQ(DrawQuad::IO_SURFACE_CONTENT, quad->material); const IOSurfaceDrawQuad* io_surface_draw_quad = IOSurfaceDrawQuad::MaterialCast(quad); - EXPECT_SIZE_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size); + EXPECT_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size); EXPECT_NE(0u, io_surface_draw_quad->io_surface_resource_id); EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB), resource_provider->TargetForTesting( @@ -4719,6 +4718,62 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise); +class LayerTreeHostTestKeepSwapPromise : public LayerTreeTest { + public: + LayerTreeHostTestKeepSwapPromise() {} + + void BeginTest() override { + layer_ = SolidColorLayer::Create(); + layer_->SetIsDrawable(true); + layer_->SetBounds(gfx::Size(10, 10)); + layer_tree_host()->SetRootLayer(layer_); + gfx::Size bounds(100, 100); + layer_tree_host()->SetViewportSize(bounds); + PostSetNeedsCommitToMainThread(); + } + + void DidCommit() override { + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&LayerTreeHostTestKeepSwapPromise::ChangeFrame, + base::Unretained(this))); + } + + void ChangeFrame() { + switch (layer_tree_host()->source_frame_number()) { + case 1: + layer_->SetBounds(gfx::Size(10, 11)); + layer_tree_host()->QueueSwapPromise( + make_scoped_ptr(new TestSwapPromise(&swap_promise_result_))); + break; + case 2: + break; + default: + NOTREACHED(); + break; + } + } + + void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { + EXPECT_TRUE(result); + if (host_impl->active_tree()->source_frame_number() >= 1) { + // The commit changes layers so it should cause a swap. + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_TRUE(swap_promise_result_.did_swap_called); + EXPECT_FALSE(swap_promise_result_.did_not_swap_called); + EXPECT_TRUE(swap_promise_result_.dtor_called); + EndTest(); + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + TestSwapPromiseResult swap_promise_result_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromise); + class LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit : public LayerTreeHostTest { protected: @@ -4780,17 +4835,9 @@ void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, bool did_handle) override { + // This is needed so that the impl-thread state matches main-thread state. + host_impl->DidLoseOutputSurface(); EndTest(); - // This lets the test finally commit and exit. - MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit:: - FindOutputSurface, - base::Unretained(this))); - } - - void FindOutputSurface() { - layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(true); } void AfterTest() override {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 3a4d36d..6a88834 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -75,7 +75,8 @@ LayerTreeImpl::LayerTreeImpl( LayerTreeHostImpl* layer_tree_host_impl, - scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor) + scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) : layer_tree_host_impl_(layer_tree_host_impl), source_frame_number_(-1), hud_layer_(0), @@ -83,12 +84,14 @@ root_layer_scroll_offset_delegate_(NULL), background_color_(0), has_transparent_background_(false), + overscroll_elasticity_layer_(NULL), page_scale_layer_(NULL), inner_viewport_scroll_layer_(NULL), outer_viewport_scroll_layer_(NULL), page_scale_factor_(page_scale_factor), min_page_scale_factor_(0), max_page_scale_factor_(0), + elastic_overscroll_(elastic_overscroll), scrolling_layer_id_from_previous_tree_(0), contents_textures_purged_(false), viewport_size_invalid_(false), @@ -230,6 +233,7 @@ // tree so only the limits need to be provided. target_tree->PushPageScaleFactorAndLimits(nullptr, min_page_scale_factor(), max_page_scale_factor()); + target_tree->elastic_overscroll()->PushPendingToActive(); target_tree->pending_page_scale_animation_ = pending_page_scale_animation_.Pass(); @@ -428,6 +432,7 @@ DCHECK(IsActiveTree()); page_scale_factor()->AbortCommit(); + elastic_overscroll()->AbortCommit(); top_controls_content_offset_ += sent_top_controls_delta_; top_controls_delta_ -= sent_top_controls_delta_; @@ -524,8 +529,9 @@ root_layer(), DrawViewportSize(), layer_tree_host_impl_->DrawTransform(), device_scale_factor(), current_page_scale_factor(), page_scale_layer, - resource_provider()->max_texture_size(), settings().can_use_lcd_text, - settings().layers_always_allowed_lcd_text, + elastic_overscroll()->Current(IsActiveTree()), + overscroll_elasticity_layer_, resource_provider()->max_texture_size(), + settings().can_use_lcd_text, settings().layers_always_allowed_lcd_text, can_render_to_separate_surface, settings().layer_transforms_should_scale_layer_contents, &render_surface_layer_list_, render_surface_layer_list_id_);
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index d16234b..46b8312 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -50,14 +50,16 @@ struct SelectionHandle; typedef std::list<UIResourceRequest> UIResourceRequestQueue; +typedef SyncedProperty<AdditionGroup<gfx::Vector2dF>> SyncedElasticOverscroll; class CC_EXPORT LayerTreeImpl { public: static scoped_ptr<LayerTreeImpl> create( LayerTreeHostImpl* layer_tree_host_impl, - scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor) { - return make_scoped_ptr( - new LayerTreeImpl(layer_tree_host_impl, page_scale_factor)); + scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) { + return make_scoped_ptr(new LayerTreeImpl( + layer_tree_host_impl, page_scale_factor, elastic_overscroll)); } virtual ~LayerTreeImpl(); @@ -179,6 +181,13 @@ SyncedProperty<ScaleGroup>* page_scale_factor(); const SyncedProperty<ScaleGroup>* page_scale_factor() const; + SyncedElasticOverscroll* elastic_overscroll() { + return elastic_overscroll_.get(); + } + const SyncedElasticOverscroll* elastic_overscroll() const { + return elastic_overscroll_.get(); + } + // Updates draw properties and render surface layer list, as well as tile // priorities. Returns false if it was unable to update. bool UpdateDrawProperties(); @@ -325,7 +334,8 @@ protected: explicit LayerTreeImpl( LayerTreeHostImpl* layer_tree_host_impl, - scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor); + scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor, + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll); void ReleaseResourcesRecursive(LayerImpl* current); float ClampPageScaleFactorToLimits(float page_scale_factor) const; void PushPageScaleFactorAndLimits(const float* page_scale_factor, @@ -360,6 +370,8 @@ float min_page_scale_factor_; float max_page_scale_factor_; + scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_; + typedef base::hash_map<int, LayerImpl*> LayerIdMap; LayerIdMap layer_id_map_;
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc index 2131d4c..78d72de 100644 --- a/cc/trees/layer_tree_impl_unittest.cc +++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -463,7 +463,7 @@ // its layout size is 50x50, positioned at 25x25. LayerImpl* test_layer = host_impl().active_tree()->root_layer()->children()[0]; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); ASSERT_EQ(1u, RenderSurfaceLayerList().size()); ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); @@ -1697,7 +1697,7 @@ // its layout size is 50x50, positioned at 25x25. LayerImpl* test_layer = host_impl().active_tree()->root_layer()->children()[0]; - EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect()); ASSERT_EQ(1u, RenderSurfaceLayerList().size()); ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); @@ -1812,8 +1812,8 @@ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size()); // Check whether the child layer fits into the root after scaled. - EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()), - test_layer->visible_content_rect()); + EXPECT_EQ(gfx::Rect(test_layer->content_bounds()), + test_layer->visible_content_rect()); // Hit checking for a point outside the layer should return a null pointer // (the root layer does not draw content, so it will not be tested either).
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc index ab44a66..508e7ea 100644 --- a/cc/trees/layer_tree_settings.cc +++ b/cc/trees/layer_tree_settings.cc
@@ -4,6 +4,7 @@ #include "cc/trees/layer_tree_settings.h" +#include <GLES2/gl2.h> #include <limits> #include "base/command_line.h" @@ -60,13 +61,12 @@ strict_layer_property_change_checking(false), use_one_copy(false), use_zero_copy(false), - use_image_external(false), + use_image_texture_target(GL_TEXTURE_2D), ignore_root_layer_flings(false), scheduled_raster_task_limit(32), use_occlusion_for_tile_prioritization(false), record_full_layer(false), - use_display_lists(false), - main_thread_should_always_be_low_latency(false) { + use_display_lists(false) { } LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h index 2660dae..1892b39 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h
@@ -72,13 +72,12 @@ bool strict_layer_property_change_checking; bool use_one_copy; bool use_zero_copy; - bool use_image_external; + unsigned use_image_texture_target; bool ignore_root_layer_flings; size_t scheduled_raster_task_limit; bool use_occlusion_for_tile_prioritization; bool record_full_layer; bool use_display_lists; - bool main_thread_should_always_be_low_latency; LayerTreeDebugState initial_debug_state; };
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 9a13457..dfce808 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -90,6 +90,7 @@ if (layer_tree_host_->settings().single_thread_proxy_scheduler && !scheduler_on_impl_thread_) { SchedulerSettings scheduler_settings(layer_tree_host_->settings()); + scheduler_settings.main_thread_should_always_be_low_latency = true; scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings,
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index f7b0c5d..454c67b 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -98,6 +98,8 @@ #define glGetVertexAttribiv GLES2_GET_FUN(GetVertexAttribiv) #define glGetVertexAttribPointerv GLES2_GET_FUN(GetVertexAttribPointerv) #define glHint GLES2_GET_FUN(Hint) +#define glInvalidateFramebuffer GLES2_GET_FUN(InvalidateFramebuffer) +#define glInvalidateSubFramebuffer GLES2_GET_FUN(InvalidateSubFramebuffer) #define glIsBuffer GLES2_GET_FUN(IsBuffer) #define glIsEnabled GLES2_GET_FUN(IsEnabled) #define glIsFramebuffer GLES2_GET_FUN(IsFramebuffer) @@ -109,6 +111,7 @@ #define glLinkProgram GLES2_GET_FUN(LinkProgram) #define glPixelStorei GLES2_GET_FUN(PixelStorei) #define glPolygonOffset GLES2_GET_FUN(PolygonOffset) +#define glReadBuffer GLES2_GET_FUN(ReadBuffer) #define glReadPixels GLES2_GET_FUN(ReadPixels) #define glReleaseShaderCompiler GLES2_GET_FUN(ReleaseShaderCompiler) #define glRenderbufferStorage GLES2_GET_FUN(RenderbufferStorage)
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 7a3db58..b057477 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -2017,6 +2017,20 @@ 'result': ['SizedResult<GLuint>'], 'client_test': False, }, + 'InvalidateFramebuffer': { + 'type': 'PUTn', + 'count': 1, + 'client_test': False, + 'unit_test': False, + 'unsafe': True, + }, + 'InvalidateSubFramebuffer': { + 'type': 'PUTn', + 'count': 1, + 'client_test': False, + 'unit_test': False, + 'unsafe': True, + }, 'IsBuffer': { 'type': 'Is', 'decoder_func': 'DoIsBuffer', @@ -2133,6 +2147,9 @@ 'unit_test': False, 'extension_flag': 'multisampled_render_to_texture', }, + 'ReadBuffer': { + 'unsafe': True, + }, 'ReadPixels': { 'cmd_comment': '// ReadPixels has the result separated from the pixel buffer so that\n' @@ -2742,8 +2759,6 @@ 'DiscardFramebufferEXT': { 'type': 'PUTn', 'count': 1, - 'cmd_args': 'GLenum target, GLsizei count, ' - 'const GLenum* attachments', 'decoder_func': 'DoDiscardFramebufferEXT', 'unit_test': False, 'client_test': False, @@ -3132,12 +3147,10 @@ self.WriteServiceHandlerFunctionHeader(func, file) self.WriteHandlerExtensionCheck(func, file) self.WriteHandlerDeferReadWrite(func, file); - last_arg = func.GetLastOriginalArg() - all_but_last_arg = func.GetOriginalArgs()[:-1] - for arg in all_but_last_arg: + for arg in func.GetOriginalArgs(): + if arg.IsPointer(): + self.WriteGetDataSizeCode(func, file) arg.WriteGetCode(file) - self.WriteGetDataSizeCode(func, file) - last_arg.WriteGetCode(file) func.WriteHandlerValidation(file) func.WriteHandlerImplementation(file) file.Write(" return error::kNoError;\n") @@ -3149,12 +3162,10 @@ self.WriteServiceHandlerFunctionHeader(func, file) self.WriteHandlerExtensionCheck(func, file) self.WriteHandlerDeferReadWrite(func, file); - last_arg = func.GetLastOriginalArg() - all_but_last_arg = func.GetOriginalArgs()[:-1] - for arg in all_but_last_arg: + for arg in func.GetOriginalArgs(): + if arg.IsPointer(): + self.WriteGetDataSizeCode(func, file) arg.WriteGetCode(file) - self.WriteGetDataSizeCode(func, file) - last_arg.WriteGetCode(file) func.WriteHandlerValidation(file) func.WriteHandlerImplementation(file) file.Write(" return error::kNoError;\n") @@ -4224,9 +4235,7 @@ SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id"); return; } - if (%(name)sHelper(%(arg_string)s)) { - helper_->%(name)s(%(arg_string)s); - } + %(name)sHelper(%(arg_string)s); CheckGLError(); } @@ -5526,13 +5535,13 @@ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n") func.WriteDestinationInitalizationValidation(file) self.WriteClientGLCallLog(func, file) - last_arg_name = func.GetLastOriginalArg().name + last_pointer_name = func.GetLastOriginalPointerArg().name file.Write(""" GPU_CLIENT_LOG_CODE_BLOCK({ for (GLsizei i = 0; i < count; ++i) { """) values_str = ' << ", " << '.join( ["%s[%d + i * %d]" % ( - last_arg_name, ndx, self.GetArrayCount(func)) for ndx in range( + last_pointer_name, ndx, self.GetArrayCount(func)) for ndx in range( 0, self.GetArrayCount(func))]) file.Write(' GPU_CLIENT_LOG(" " << i << ": " << %s);\n' % values_str) file.Write(" }\n });\n") @@ -5560,18 +5569,26 @@ data[ii][jj] = static_cast<%(type)s>(ii * %(count)d + jj); } } - expected.cmd.Init(%(cmd_args)s, &data[0][0]); - gl_->%(name)s(%(args)s, &data[0][0]); + expected.cmd.Init(%(cmd_args)s); + gl_->%(name)s(%(args)s); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } """ - cmd_arg_strings = [ - arg.GetValidClientSideCmdArg(func) for arg in func.GetCmdArgs()[0:-2] - ] + cmd_arg_strings = [] + for arg in func.GetCmdArgs(): + if arg.name.endswith("_shm_id"): + cmd_arg_strings.append("&data[0][0]") + elif arg.name.endswith("_shm_offset"): + continue + else: + cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func)) gl_arg_strings = [] count_param = 0 - for arg in func.GetOriginalArgs()[0:-1]: - valid_value = arg.GetValidClientSideArg(func) + for arg in func.GetOriginalArgs(): + if arg.IsPointer(): + valid_value = "&data[0][0]" + else: + valid_value = arg.GetValidClientSideArg(func) gl_arg_strings.append(valid_value) if arg.name == "count": count_param = int(valid_value) @@ -5600,7 +5617,7 @@ data[ii][jj] = static_cast<%(type)s>(ii * %(count)d + jj); } } - gl_->%(name)s(%(args)s, &data[0][0]); + gl_->%(name)s(%(args)s); EXPECT_TRUE(NoCommandsWritten()); EXPECT_EQ(%(gl_error)s, CheckError()); } @@ -5608,9 +5625,11 @@ for invalid_arg in constants: gl_arg_strings = [] invalid = invalid_arg.GetInvalidArg(func) - for arg in func.GetOriginalArgs()[0:-1]: + for arg in func.GetOriginalArgs(): if arg is invalid_arg: gl_arg_strings.append(invalid[0]) + elif arg.IsPointer(): + gl_arg_strings.append("&data[0][0]") else: valid_value = arg.GetValidClientSideArg(func) gl_arg_strings.append(valid_value) @@ -5653,28 +5672,24 @@ def WriteImmediateCmdInit(self, func, file): """Overrriden from TypeHandler.""" - last_arg = func.GetLastOriginalArg() - file.Write(" void Init(%s, %s _%s) {\n" % - (func.MakeTypedCmdArgString("_"), - last_arg.type, last_arg.name)) + file.Write(" void Init(%s) {\n" % + func.MakeTypedInitString("_")) file.Write(" SetHeader(_count);\n") args = func.GetCmdArgs() for arg in args: file.Write(" %s = _%s;\n" % (arg.name, arg.name)) file.Write(" memcpy(ImmediateDataAddress(this),\n") - file.Write(" _%s, ComputeDataSize(_count));\n" % last_arg.name) + pointer_arg = func.GetLastOriginalPointerArg() + file.Write(" _%s, ComputeDataSize(_count));\n" % pointer_arg.name) file.Write(" }\n") file.Write("\n") def WriteImmediateCmdSet(self, func, file): """Overrriden from TypeHandler.""" - last_arg = func.GetLastOriginalArg() - copy_args = func.MakeCmdArgString("_", False) - file.Write(" void* Set(void* cmd%s, %s _%s) {\n" % - (func.MakeTypedCmdArgString("_", True), - last_arg.type, last_arg.name)) - file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" % - (copy_args, last_arg.name)) + file.Write(" void* Set(void* cmd%s) {\n" % + func.MakeTypedInitString("_", True)) + file.Write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % + func.MakeInitString("_")) file.Write(" const uint32_t size = ComputeSize(_count);\n") file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>(" "cmd, size);\n") @@ -5701,7 +5716,7 @@ def WriteImmediateFormatTest(self, func, file): """Overrriden from TypeHandler.""" - args = func.GetCmdArgs() + args = func.GetOriginalArgs() count_param = 0 for arg in args: if arg.name == "count": @@ -5722,13 +5737,20 @@ file.Write(" void* next_cmd = cmd.Set(\n") file.Write(" &cmd") for value, arg in enumerate(args): - file.Write(",\n static_cast<%s>(%d)" % (arg.type, value + 1)) - file.Write(",\n data);\n") + if arg.IsPointer(): + file.Write(",\n data") + elif arg.IsConstant(): + continue + else: + file.Write(",\n static_cast<%s>(%d)" % (arg.type, value + 1)) + file.Write(");\n") file.Write(" EXPECT_EQ(static_cast<uint32_t>(cmds::%s::kCmdId),\n" % func.name) file.Write(" cmd.header.command);\n") file.Write(" EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);\n") for value, arg in enumerate(args): + if arg.IsPointer() or arg.IsConstant(): + continue file.Write(" EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" % (arg.type, value + 1, arg.name)) file.Write(" CheckBytesWrittenMatchesExpectedSize(\n") @@ -6978,6 +7000,13 @@ self.num_pointer_args = sum( [1 for arg in self.args_for_cmds if arg.IsPointer()]) + if self.num_pointer_args > 0: + for arg in reversed(self.original_args): + if arg.IsPointer(): + self.last_original_pointer_arg = arg + break + else: + self.last_original_pointer_arg = None self.info = info self.type_handler = self.type_handlers[info['type']] self.can_auto_generate = (self.num_pointer_args == 0 and @@ -7124,6 +7153,9 @@ """Gets the last original argument to this function.""" return self.original_args[len(self.original_args) - 1] + def GetLastOriginalPointerArg(self): + return self.last_original_pointer_arg + def __MaybePrependComma(self, arg_string, add_comma): """Adds a comma if arg_string is not empty and add_comma is true.""" comma = ""
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 727d39a..c1a1114 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -378,6 +378,21 @@ void GLES2Hint(GLenum target, GLenum mode) { gles2::GetGLContext()->Hint(target, mode); } +void GLES2InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) { + gles2::GetGLContext()->InvalidateFramebuffer(target, count, attachments); +} +void GLES2InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { + gles2::GetGLContext()->InvalidateSubFramebuffer(target, count, attachments, x, + y, width, height); +} GLboolean GLES2IsBuffer(GLuint buffer) { return gles2::GetGLContext()->IsBuffer(buffer); } @@ -411,6 +426,9 @@ void GLES2PolygonOffset(GLfloat factor, GLfloat units) { gles2::GetGLContext()->PolygonOffset(factor, units); } +void GLES2ReadBuffer(GLenum src) { + gles2::GetGLContext()->ReadBuffer(src); +} void GLES2ReadPixels(GLint x, GLint y, GLsizei width, @@ -1415,6 +1433,14 @@ reinterpret_cast<GLES2FunctionPointer>(glHint), }, { + "glInvalidateFramebuffer", + reinterpret_cast<GLES2FunctionPointer>(glInvalidateFramebuffer), + }, + { + "glInvalidateSubFramebuffer", + reinterpret_cast<GLES2FunctionPointer>(glInvalidateSubFramebuffer), + }, + { "glIsBuffer", reinterpret_cast<GLES2FunctionPointer>(glIsBuffer), }, @@ -1459,6 +1485,10 @@ reinterpret_cast<GLES2FunctionPointer>(glPolygonOffset), }, { + "glReadBuffer", + reinterpret_cast<GLES2FunctionPointer>(glReadBuffer), + }, + { "glReadPixels", reinterpret_cast<GLES2FunctionPointer>(glReadPixels), },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index b8e3b66..dc43a41 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -813,6 +813,36 @@ } } +void InvalidateFramebufferImmediate(GLenum target, + GLsizei count, + const GLenum* attachments) { + const uint32_t size = + gles2::cmds::InvalidateFramebufferImmediate::ComputeSize(count); + gles2::cmds::InvalidateFramebufferImmediate* c = + GetImmediateCmdSpaceTotalSize< + gles2::cmds::InvalidateFramebufferImmediate>(size); + if (c) { + c->Init(target, count, attachments); + } +} + +void InvalidateSubFramebufferImmediate(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { + const uint32_t size = + gles2::cmds::InvalidateSubFramebufferImmediate::ComputeSize(count); + gles2::cmds::InvalidateSubFramebufferImmediate* c = + GetImmediateCmdSpaceTotalSize< + gles2::cmds::InvalidateSubFramebufferImmediate>(size); + if (c) { + c->Init(target, count, attachments, x, y, width, height); + } +} + void IsBuffer(GLuint buffer, uint32_t result_shm_id, uint32_t result_shm_offset) { @@ -902,6 +932,13 @@ } } +void ReadBuffer(GLenum src) { + gles2::cmds::ReadBuffer* c = GetCmdSpace<gles2::cmds::ReadBuffer>(); + if (c) { + c->Init(src); + } +} + void ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 1916e7d..4c148e9 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2314,7 +2314,7 @@ // the old model but possibly not true in the new model if another context has // deleted the resource. -bool GLES2Implementation::BindBufferHelper( +void GLES2Implementation::BindBufferHelper( GLenum target, GLuint buffer_id) { // TODO(gman): See note #1 above. bool changed = false; @@ -2340,11 +2340,19 @@ } // TODO(gman): There's a bug here. If the target is invalid the ID will not be // used even though it's marked it as used here. - GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer_id); - return changed; + if (changed) { + GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind( + this, target, buffer_id, &GLES2Implementation::BindBufferStub); + } } -bool GLES2Implementation::BindFramebufferHelper( +void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) { + helper_->BindBuffer(target, buffer); + if (share_group_->bind_generates_resource()) + helper_->CommandBufferHelper::Flush(); +} + +void GLES2Implementation::BindFramebufferHelper( GLenum target, GLuint framebuffer) { // TODO(gman): See note #1 above. bool changed = false; @@ -2360,7 +2368,7 @@ case GL_READ_FRAMEBUFFER: if (!IsChromiumFramebufferMultisampleAvailable()) { SetGLErrorInvalidEnum("glBindFramebuffer", target, "target"); - return false; + return; } if (bound_read_framebuffer_ != framebuffer) { bound_read_framebuffer_ = framebuffer; @@ -2370,7 +2378,7 @@ case GL_DRAW_FRAMEBUFFER: if (!IsChromiumFramebufferMultisampleAvailable()) { SetGLErrorInvalidEnum("glBindFramebuffer", target, "target"); - return false; + return; } if (bound_framebuffer_ != framebuffer) { bound_framebuffer_ = framebuffer; @@ -2379,13 +2387,23 @@ break; default: SetGLErrorInvalidEnum("glBindFramebuffer", target, "target"); - return false; + return; } - GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer); - return changed; + + if (changed) { + GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind( + this, target, framebuffer, &GLES2Implementation::BindFramebufferStub); + } } -bool GLES2Implementation::BindRenderbufferHelper( +void GLES2Implementation::BindFramebufferStub(GLenum target, + GLuint framebuffer) { + helper_->BindFramebuffer(target, framebuffer); + if (share_group_->bind_generates_resource()) + helper_->CommandBufferHelper::Flush(); +} + +void GLES2Implementation::BindRenderbufferHelper( GLenum target, GLuint renderbuffer) { // TODO(gman): See note #1 above. bool changed = false; @@ -2402,11 +2420,21 @@ } // TODO(gman): There's a bug here. If the target is invalid the ID will not be // used even though it's marked it as used here. - GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer); - return changed; + if (changed) { + GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind( + this, target, renderbuffer, + &GLES2Implementation::BindRenderbufferStub); + } } -bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) { +void GLES2Implementation::BindRenderbufferStub(GLenum target, + GLuint renderbuffer) { + helper_->BindRenderbuffer(target, renderbuffer); + if (share_group_->bind_generates_resource()) + helper_->CommandBufferHelper::Flush(); +} + +void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) { // TODO(gman): See note #1 above. // TODO(gman): Change this to false once we figure out why it's failing // on daisy. @@ -2437,26 +2465,37 @@ } // TODO(gman): There's a bug here. If the target is invalid the ID will not be // used. even though it's marked it as used here. - GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture); - return changed; + if (changed) { + GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind( + this, target, texture, &GLES2Implementation::BindTextureStub); + } } -bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array) { +void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) { + helper_->BindTexture(target, texture); + if (share_group_->bind_generates_resource()) + helper_->CommandBufferHelper::Flush(); +} + +void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) { // TODO(gman): See note #1 above. bool changed = false; - if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) { + if (vertex_array_object_manager_->BindVertexArray(array, &changed)) { + if (changed) { + // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind + // because unlike other resources VertexArrayObject ids must + // be generated by GenVertexArrays. A random id to Bind will not + // generate a new object. + helper_->BindVertexArrayOES(array); + } + } else { SetGLError( GL_INVALID_OPERATION, "glBindVertexArrayOES", "id was not generated with glGenVertexArrayOES"); } - // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind - // because unlike other resources VertexArrayObject ids must - // be generated by GenVertexArrays. A random id to Bind will not - // generate a new object. - return changed; } -bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target, +void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer) { bool changed = false; switch (target) { @@ -2472,17 +2511,25 @@ } // TODO(gman): There's a bug here. If the target is invalid the ID will not be // used even though it's marked it as used here. - GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(valuebuffer); - return changed; + if (changed) { + GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind( + this, target, valuebuffer, + &GLES2Implementation::BindValuebufferCHROMIUMStub); + } } -bool GLES2Implementation::UseProgramHelper(GLuint program) { - bool changed = false; +void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target, + GLuint valuebuffer) { + helper_->BindValuebufferCHROMIUM(target, valuebuffer); + if (share_group_->bind_generates_resource()) + helper_->CommandBufferHelper::Flush(); +} + +void GLES2Implementation::UseProgramHelper(GLuint program) { if (current_program_ != program) { current_program_ = program; - changed = true; + helper_->UseProgram(program); } - return changed; } bool GLES2Implementation::IsBufferReservedId(GLuint id) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 77b8a87..df6e014 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -432,13 +432,19 @@ bool IsProgramReservedId(GLuint id) { return false; } bool IsValuebufferReservedId(GLuint id) { return false; } - bool BindBufferHelper(GLenum target, GLuint texture); - bool BindFramebufferHelper(GLenum target, GLuint texture); - bool BindRenderbufferHelper(GLenum target, GLuint texture); - bool BindTextureHelper(GLenum target, GLuint texture); - bool BindVertexArrayOESHelper(GLuint array); - bool BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer); - bool UseProgramHelper(GLuint program); + void BindBufferHelper(GLenum target, GLuint buffer); + void BindFramebufferHelper(GLenum target, GLuint framebuffer); + void BindRenderbufferHelper(GLenum target, GLuint renderbuffer); + void BindTextureHelper(GLenum target, GLuint texture); + void BindVertexArrayOESHelper(GLuint array); + void BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer); + void UseProgramHelper(GLuint program); + + void BindBufferStub(GLenum target, GLuint buffer); + void BindFramebufferStub(GLenum target, GLuint framebuffer); + void BindRenderbufferStub(GLenum target, GLuint renderbuffer); + void BindTextureStub(GLenum target, GLuint texture); + void BindValuebufferCHROMIUMStub(GLenum target, GLuint valuebuffer); void GenBuffersHelper(GLsizei n, const GLuint* buffers); void GenFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 66cfcef..48bccd5 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -278,6 +278,18 @@ void Hint(GLenum target, GLenum mode) override; +void InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) override; + +void InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) override; + GLboolean IsBuffer(GLuint buffer) override; GLboolean IsEnabled(GLenum cap) override; @@ -300,6 +312,8 @@ void PolygonOffset(GLfloat factor, GLfloat units) override; +void ReadBuffer(GLenum src) override; + void ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h index d67e7ed..d7a45ce 100644 --- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -30,9 +30,7 @@ SetGLError(GL_INVALID_OPERATION, "BindBuffer", "buffer reserved id"); return; } - if (BindBufferHelper(target, buffer)) { - helper_->BindBuffer(target, buffer); - } + BindBufferHelper(target, buffer); CheckGLError(); } @@ -46,9 +44,7 @@ "framebuffer reserved id"); return; } - if (BindFramebufferHelper(target, framebuffer)) { - helper_->BindFramebuffer(target, framebuffer); - } + BindFramebufferHelper(target, framebuffer); CheckGLError(); } @@ -62,9 +58,7 @@ "renderbuffer reserved id"); return; } - if (BindRenderbufferHelper(target, renderbuffer)) { - helper_->BindRenderbuffer(target, renderbuffer); - } + BindRenderbufferHelper(target, renderbuffer); CheckGLError(); } @@ -77,9 +71,7 @@ SetGLError(GL_INVALID_OPERATION, "BindTexture", "texture reserved id"); return; } - if (BindTextureHelper(target, texture)) { - helper_->BindTexture(target, texture); - } + BindTextureHelper(target, texture); CheckGLError(); } @@ -1032,6 +1024,62 @@ CheckGLError(); } +void GLES2Implementation::InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateFramebuffer(" + << GLES2Util::GetStringFrameBufferTarget(target) << ", " + << count << ", " << static_cast<const void*>(attachments) + << ")"); + GPU_CLIENT_LOG_CODE_BLOCK({ + for (GLsizei i = 0; i < count; ++i) { + GPU_CLIENT_LOG(" " << i << ": " << attachments[0 + i * 1]); + } + }); + if (count < 0) { + SetGLError(GL_INVALID_VALUE, "glInvalidateFramebuffer", "count < 0"); + return; + } + helper_->InvalidateFramebufferImmediate(target, count, attachments); + CheckGLError(); +} + +void GLES2Implementation::InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateSubFramebuffer(" + << GLES2Util::GetStringFrameBufferTarget(target) << ", " + << count << ", " << static_cast<const void*>(attachments) + << ", " << x << ", " << y << ", " << width << ", " + << height << ")"); + GPU_CLIENT_LOG_CODE_BLOCK({ + for (GLsizei i = 0; i < count; ++i) { + GPU_CLIENT_LOG(" " << i << ": " << attachments[0 + i * 1]); + } + }); + if (count < 0) { + SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "count < 0"); + return; + } + if (width < 0) { + SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "width < 0"); + return; + } + if (height < 0) { + SetGLError(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", "height < 0"); + return; + } + helper_->InvalidateSubFramebufferImmediate(target, count, attachments, x, y, + width, height); + CheckGLError(); +} + GLboolean GLES2Implementation::IsBuffer(GLuint buffer) { GPU_CLIENT_SINGLE_THREAD_CHECK(); TRACE_EVENT0("gpu", "GLES2Implementation::IsBuffer"); @@ -1157,6 +1205,14 @@ CheckGLError(); } +void GLES2Implementation::ReadBuffer(GLenum src) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadBuffer(" + << GLES2Util::GetStringEnum(src) << ")"); + helper_->ReadBuffer(src); + CheckGLError(); +} + void GLES2Implementation::ReleaseShaderCompiler() { GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReleaseShaderCompiler(" @@ -1997,9 +2053,7 @@ SetGLError(GL_INVALID_OPERATION, "UseProgram", "program reserved id"); return; } - if (UseProgramHelper(program)) { - helper_->UseProgram(program); - } + UseProgramHelper(program); CheckGLError(); } @@ -2408,9 +2462,7 @@ SetGLError(GL_INVALID_OPERATION, "BindVertexArrayOES", "array reserved id"); return; } - if (BindVertexArrayOESHelper(array)) { - helper_->BindVertexArrayOES(array); - } + BindVertexArrayOESHelper(array); CheckGLError(); } @@ -2558,9 +2610,7 @@ "valuebuffer reserved id"); return; } - if (BindValuebufferCHROMIUMHelper(target, valuebuffer)) { - helper_->BindValuebufferCHROMIUM(target, valuebuffer); - } + BindValuebufferCHROMIUMHelper(target, valuebuffer); CheckGLError(); }
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index f48e9ab..3d0eaa2 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -810,6 +810,42 @@ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } +TEST_F(GLES2ImplementationTest, InvalidateFramebuffer) { + GLenum data[2][1] = {{0}}; + struct Cmds { + cmds::InvalidateFramebufferImmediate cmd; + GLenum data[2][1]; + }; + + Cmds expected; + for (int ii = 0; ii < 2; ++ii) { + for (int jj = 0; jj < 1; ++jj) { + data[ii][jj] = static_cast<GLenum>(ii * 1 + jj); + } + } + expected.cmd.Init(GL_FRAMEBUFFER, 2, &data[0][0]); + gl_->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, &data[0][0]); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, InvalidateSubFramebuffer) { + GLenum data[2][1] = {{0}}; + struct Cmds { + cmds::InvalidateSubFramebufferImmediate cmd; + GLenum data[2][1]; + }; + + Cmds expected; + for (int ii = 0; ii < 2; ++ii) { + for (int jj = 0; jj < 1; ++jj) { + data[ii][jj] = static_cast<GLenum>(ii * 1 + jj); + } + } + expected.cmd.Init(GL_FRAMEBUFFER, 2, &data[0][0], 4, 5, 6, 7); + gl_->InvalidateSubFramebuffer(GL_FRAMEBUFFER, 2, &data[0][0], 4, 5, 6, 7); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + TEST_F(GLES2ImplementationTest, IsBuffer) { struct Cmds { cmds::IsBuffer cmd; @@ -987,6 +1023,17 @@ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } +TEST_F(GLES2ImplementationTest, ReadBuffer) { + struct Cmds { + cmds::ReadBuffer cmd; + }; + Cmds expected; + expected.cmd.Init(1); + + gl_->ReadBuffer(1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + TEST_F(GLES2ImplementationTest, ReleaseShaderCompiler) { struct Cmds { cmds::ReleaseShaderCompiler cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index f8c2707..5970747 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -206,6 +206,16 @@ GLenum pname, void** pointer) = 0; virtual void Hint(GLenum target, GLenum mode) = 0; +virtual void InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) = 0; +virtual void InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) = 0; virtual GLboolean IsBuffer(GLuint buffer) = 0; virtual GLboolean IsEnabled(GLenum cap) = 0; virtual GLboolean IsFramebuffer(GLuint framebuffer) = 0; @@ -217,6 +227,7 @@ virtual void LinkProgram(GLuint program) = 0; virtual void PixelStorei(GLenum pname, GLint param) = 0; virtual void PolygonOffset(GLfloat factor, GLfloat units) = 0; +virtual void ReadBuffer(GLenum src) = 0; virtual void ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index 5d8a40a..01a7e07 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -201,6 +201,16 @@ GLenum pname, void** pointer) override; void Hint(GLenum target, GLenum mode) override; +void InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) override; +void InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) override; GLboolean IsBuffer(GLuint buffer) override; GLboolean IsEnabled(GLenum cap) override; GLboolean IsFramebuffer(GLuint framebuffer) override; @@ -212,6 +222,7 @@ void LinkProgram(GLuint program) override; void PixelStorei(GLenum pname, GLint param) override; void PolygonOffset(GLfloat factor, GLfloat units) override; +void ReadBuffer(GLenum src) override; void ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index b4792ca..a5797f0 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -331,6 +331,20 @@ } void GLES2InterfaceStub::Hint(GLenum /* target */, GLenum /* mode */) { } +void GLES2InterfaceStub::InvalidateFramebuffer( + GLenum /* target */, + GLsizei /* count */, + const GLenum* /* attachments */) { +} +void GLES2InterfaceStub::InvalidateSubFramebuffer( + GLenum /* target */, + GLsizei /* count */, + const GLenum* /* attachments */, + GLint /* x */, + GLint /* y */, + GLsizei /* width */, + GLsizei /* height */) { +} GLboolean GLES2InterfaceStub::IsBuffer(GLuint /* buffer */) { return 0; } @@ -361,6 +375,8 @@ void GLES2InterfaceStub::PolygonOffset(GLfloat /* factor */, GLfloat /* units */) { } +void GLES2InterfaceStub::ReadBuffer(GLenum /* src */) { +} void GLES2InterfaceStub::ReadPixels(GLint /* x */, GLint /* y */, GLsizei /* width */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 72860f1..b88ec6a 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -201,6 +201,16 @@ GLenum pname, void** pointer) override; void Hint(GLenum target, GLenum mode) override; +void InvalidateFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments) override; +void InvalidateSubFramebuffer(GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) override; GLboolean IsBuffer(GLuint buffer) override; GLboolean IsEnabled(GLenum cap) override; GLboolean IsFramebuffer(GLuint framebuffer) override; @@ -212,6 +222,7 @@ void LinkProgram(GLuint program) override; void PixelStorei(GLenum pname, GLint param) override; void PolygonOffset(GLfloat factor, GLfloat units) override; +void ReadBuffer(GLenum src) override; void ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 28e6f43..70729c3 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -577,6 +577,27 @@ gl_->Hint(target, mode); } +void GLES2TraceImplementation::InvalidateFramebuffer( + GLenum target, + GLsizei count, + const GLenum* attachments) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InvalidateFramebuffer"); + gl_->InvalidateFramebuffer(target, count, attachments); +} + +void GLES2TraceImplementation::InvalidateSubFramebuffer( + GLenum target, + GLsizei count, + const GLenum* attachments, + GLint x, + GLint y, + GLsizei width, + GLsizei height) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InvalidateSubFramebuffer"); + gl_->InvalidateSubFramebuffer(target, count, attachments, x, y, width, + height); +} + GLboolean GLES2TraceImplementation::IsBuffer(GLuint buffer) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsBuffer"); return gl_->IsBuffer(buffer); @@ -632,6 +653,11 @@ gl_->PolygonOffset(factor, units); } +void GLES2TraceImplementation::ReadBuffer(GLenum src) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ReadBuffer"); + gl_->ReadBuffer(src); +} + void GLES2TraceImplementation::ReadPixels(GLint x, GLint y, GLsizei width,
diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc index c7e3845..b5261ee 100644 --- a/gpu/command_buffer/client/share_group.cc +++ b/gpu/command_buffer/client/share_group.cc
@@ -67,11 +67,14 @@ } // Overridden from IdHandlerInterface. - bool MarkAsUsedForBind(GLuint id) override { - if (id == 0) - return true; + bool MarkAsUsedForBind(GLES2Implementation* gl_impl, + GLenum target, + GLuint id, + BindFn bind_fn) override { base::AutoLock auto_lock(lock_); - return id_allocator_.MarkAsUsed(id); + bool result = id ? id_allocator_.MarkAsUsed(id) : true; + (gl_impl->*bind_fn)(target, id); + return result; } void FreeContext(GLES2Implementation* gl_impl) override {} @@ -147,13 +150,20 @@ } // Overridden from IdHandler. - bool MarkAsUsedForBind(GLuint id) override { + bool MarkAsUsedForBind(GLES2Implementation* gl_impl, + GLenum target, + GLuint id, + BindFn bind_fn) override { #ifndef NDEBUG if (id != 0) { base::AutoLock auto_lock(lock_); DCHECK(id_states_[id - 1] == kIdInUse); } #endif + // StrictIdHandler is used if |bind_generates_resource| is false. In that + // case, |bind_fn| will not use Flush() after helper->Bind*(), so it is OK + // to call |bind_fn| without holding the lock. + (gl_impl->*bind_fn)(target, id); return true; } @@ -218,7 +228,10 @@ } // Overridden from IdHandlerInterface. - bool MarkAsUsedForBind(GLuint /* id */) override { + bool MarkAsUsedForBind(GLES2Implementation* /* gl_impl */, + GLenum /* target */, + GLuint /* id */, + BindFn /* bind_fn */) override { // This is only used for Shaders and Programs which have no bind. return false; }
diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h index c66704b..09d960b 100644 --- a/gpu/command_buffer/client/share_group.h +++ b/gpu/command_buffer/client/share_group.h
@@ -19,6 +19,7 @@ class ProgramInfoManager; typedef void (GLES2Implementation::*DeleteFn)(GLsizei n, const GLuint* ids); +typedef void (GLES2Implementation::*BindFn)(GLenum target, GLuint id); class ShareGroupContextData { public: @@ -55,7 +56,11 @@ DeleteFn delete_fn) = 0; // Marks an id as used for glBind functions. id = 0 does nothing. - virtual bool MarkAsUsedForBind(GLuint id) = 0; + virtual bool MarkAsUsedForBind( + GLES2Implementation* gl_impl, + GLenum target, + GLuint id, + BindFn bind_fn) = 0; // Called when a context in the share group is destructed. virtual void FreeContext(GLES2Implementation* gl_impl) = 0;
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index dc613b9..03b851f 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -88,6 +88,8 @@ GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenumVertexAttribute pname, GLint* params); GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenumVertexPointer pname, void** pointer); GL_APICALL void GL_APIENTRY glHint (GLenumHintTarget target, GLenumHintMode mode); +GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments); +GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLidBuffer buffer); GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenumCapability cap); GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLidFramebuffer framebuffer); @@ -99,6 +101,7 @@ GL_APICALL void GL_APIENTRY glLinkProgram (GLidProgram program); GL_APICALL void GL_APIENTRY glPixelStorei (GLenumPixelStore pname, GLintPixelStoreAlignment param); GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src); GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenumReadPixelFormat format, GLenumPixelType type, void* pixels); GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenumRenderBufferTarget target, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index c451b98..923d5a1 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -3962,6 +3962,131 @@ COMPILE_ASSERT(offsetof(Hint, target) == 4, OffsetOf_Hint_target_not_4); COMPILE_ASSERT(offsetof(Hint, mode) == 8, OffsetOf_Hint_mode_not_8); +struct InvalidateFramebufferImmediate { + typedef InvalidateFramebufferImmediate ValueType; + static const CommandId kCmdId = kInvalidateFramebufferImmediate; + static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeDataSize(GLsizei count) { + return static_cast<uint32_t>(sizeof(GLenum) * 1 * count); // NOLINT + } + + static uint32_t ComputeSize(GLsizei count) { + return static_cast<uint32_t>(sizeof(ValueType) + + ComputeDataSize(count)); // NOLINT + } + + void SetHeader(GLsizei count) { + header.SetCmdByTotalSize<ValueType>(ComputeSize(count)); + } + + void Init(GLenum _target, GLsizei _count, const GLenum* _attachments) { + SetHeader(_count); + target = _target; + count = _count; + memcpy(ImmediateDataAddress(this), _attachments, ComputeDataSize(_count)); + } + + void* Set(void* cmd, + GLenum _target, + GLsizei _count, + const GLenum* _attachments) { + static_cast<ValueType*>(cmd)->Init(_target, _count, _attachments); + const uint32_t size = ComputeSize(_count); + return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size); + } + + gpu::CommandHeader header; + uint32_t target; + int32_t count; +}; + +COMPILE_ASSERT(sizeof(InvalidateFramebufferImmediate) == 12, + Sizeof_InvalidateFramebufferImmediate_is_not_12); +COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, header) == 0, + OffsetOf_InvalidateFramebufferImmediate_header_not_0); +COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, target) == 4, + OffsetOf_InvalidateFramebufferImmediate_target_not_4); +COMPILE_ASSERT(offsetof(InvalidateFramebufferImmediate, count) == 8, + OffsetOf_InvalidateFramebufferImmediate_count_not_8); + +struct InvalidateSubFramebufferImmediate { + typedef InvalidateSubFramebufferImmediate ValueType; + static const CommandId kCmdId = kInvalidateSubFramebufferImmediate; + static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeDataSize(GLsizei count) { + return static_cast<uint32_t>(sizeof(GLenum) * 1 * count); // NOLINT + } + + static uint32_t ComputeSize(GLsizei count) { + return static_cast<uint32_t>(sizeof(ValueType) + + ComputeDataSize(count)); // NOLINT + } + + void SetHeader(GLsizei count) { + header.SetCmdByTotalSize<ValueType>(ComputeSize(count)); + } + + void Init(GLenum _target, + GLsizei _count, + const GLenum* _attachments, + GLint _x, + GLint _y, + GLsizei _width, + GLsizei _height) { + SetHeader(_count); + target = _target; + count = _count; + x = _x; + y = _y; + width = _width; + height = _height; + memcpy(ImmediateDataAddress(this), _attachments, ComputeDataSize(_count)); + } + + void* Set(void* cmd, + GLenum _target, + GLsizei _count, + const GLenum* _attachments, + GLint _x, + GLint _y, + GLsizei _width, + GLsizei _height) { + static_cast<ValueType*>(cmd) + ->Init(_target, _count, _attachments, _x, _y, _width, _height); + const uint32_t size = ComputeSize(_count); + return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size); + } + + gpu::CommandHeader header; + uint32_t target; + int32_t count; + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + +COMPILE_ASSERT(sizeof(InvalidateSubFramebufferImmediate) == 28, + Sizeof_InvalidateSubFramebufferImmediate_is_not_28); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, header) == 0, + OffsetOf_InvalidateSubFramebufferImmediate_header_not_0); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, target) == 4, + OffsetOf_InvalidateSubFramebufferImmediate_target_not_4); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, count) == 8, + OffsetOf_InvalidateSubFramebufferImmediate_count_not_8); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, x) == 12, + OffsetOf_InvalidateSubFramebufferImmediate_x_not_12); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, y) == 16, + OffsetOf_InvalidateSubFramebufferImmediate_y_not_16); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, width) == 20, + OffsetOf_InvalidateSubFramebufferImmediate_width_not_20); +COMPILE_ASSERT(offsetof(InvalidateSubFramebufferImmediate, height) == 24, + OffsetOf_InvalidateSubFramebufferImmediate_height_not_24); + struct IsBuffer { typedef IsBuffer ValueType; static const CommandId kCmdId = kIsBuffer; @@ -4426,6 +4551,37 @@ COMPILE_ASSERT(offsetof(PolygonOffset, units) == 8, OffsetOf_PolygonOffset_units_not_8); +struct ReadBuffer { + typedef ReadBuffer ValueType; + static const CommandId kCmdId = kReadBuffer; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _src) { + SetHeader(); + src = _src; + } + + void* Set(void* cmd, GLenum _src) { + static_cast<ValueType*>(cmd)->Init(_src); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t src; +}; + +COMPILE_ASSERT(sizeof(ReadBuffer) == 8, Sizeof_ReadBuffer_is_not_8); +COMPILE_ASSERT(offsetof(ReadBuffer, header) == 0, + OffsetOf_ReadBuffer_header_not_0); +COMPILE_ASSERT(offsetof(ReadBuffer, src) == 4, OffsetOf_ReadBuffer_src_not_4); + // ReadPixels has the result separated from the pixel buffer so that // it is easier to specify the result going to some specific place // that exactly fits the rectangle of pixels.
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index acc5e77..7473650 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -1218,6 +1218,59 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, InvalidateFramebufferImmediate) { + const int kSomeBaseValueToTestWith = 51; + static GLenum data[] = { + static_cast<GLenum>(kSomeBaseValueToTestWith + 0), + static_cast<GLenum>(kSomeBaseValueToTestWith + 1), + }; + cmds::InvalidateFramebufferImmediate& cmd = + *GetBufferAs<cmds::InvalidateFramebufferImmediate>(); + const GLsizei kNumElements = 2; + const size_t kExpectedCmdSize = + sizeof(cmd) + kNumElements * sizeof(GLenum) * 1; + void* next_cmd = + cmd.Set(&cmd, static_cast<GLenum>(1), static_cast<GLsizei>(2), data); + EXPECT_EQ(static_cast<uint32_t>(cmds::InvalidateFramebufferImmediate::kCmdId), + cmd.header.command); + EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(1), cmd.target); + EXPECT_EQ(static_cast<GLsizei>(2), cmd.count); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data))); + // TODO(gman): Check that data was inserted; +} + +TEST_F(GLES2FormatTest, InvalidateSubFramebufferImmediate) { + const int kSomeBaseValueToTestWith = 51; + static GLenum data[] = { + static_cast<GLenum>(kSomeBaseValueToTestWith + 0), + static_cast<GLenum>(kSomeBaseValueToTestWith + 1), + }; + cmds::InvalidateSubFramebufferImmediate& cmd = + *GetBufferAs<cmds::InvalidateSubFramebufferImmediate>(); + const GLsizei kNumElements = 2; + const size_t kExpectedCmdSize = + sizeof(cmd) + kNumElements * sizeof(GLenum) * 1; + void* next_cmd = + cmd.Set(&cmd, static_cast<GLenum>(1), static_cast<GLsizei>(2), data, + static_cast<GLint>(4), static_cast<GLint>(5), + static_cast<GLsizei>(6), static_cast<GLsizei>(7)); + EXPECT_EQ( + static_cast<uint32_t>(cmds::InvalidateSubFramebufferImmediate::kCmdId), + cmd.header.command); + EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(1), cmd.target); + EXPECT_EQ(static_cast<GLsizei>(2), cmd.count); + EXPECT_EQ(static_cast<GLint>(4), cmd.x); + EXPECT_EQ(static_cast<GLint>(5), cmd.y); + EXPECT_EQ(static_cast<GLsizei>(6), cmd.width); + EXPECT_EQ(static_cast<GLsizei>(7), cmd.height); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data))); + // TODO(gman): Check that data was inserted; +} + TEST_F(GLES2FormatTest, IsBuffer) { cmds::IsBuffer& cmd = *GetBufferAs<cmds::IsBuffer>(); void* next_cmd = @@ -1354,6 +1407,16 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, ReadBuffer) { + cmds::ReadBuffer& cmd = *GetBufferAs<cmds::ReadBuffer>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11)); + EXPECT_EQ(static_cast<uint32_t>(cmds::ReadBuffer::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.src); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, ReadPixels) { cmds::ReadPixels& cmd = *GetBufferAs<cmds::ReadPixels>(); void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11), static_cast<GLint>(12),
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index f1bb286..94aa86c 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -98,148 +98,151 @@ OP(GetVertexAttribiv) /* 339 */ \ OP(GetVertexAttribPointerv) /* 340 */ \ OP(Hint) /* 341 */ \ - OP(IsBuffer) /* 342 */ \ - OP(IsEnabled) /* 343 */ \ - OP(IsFramebuffer) /* 344 */ \ - OP(IsProgram) /* 345 */ \ - OP(IsRenderbuffer) /* 346 */ \ - OP(IsShader) /* 347 */ \ - OP(IsTexture) /* 348 */ \ - OP(LineWidth) /* 349 */ \ - OP(LinkProgram) /* 350 */ \ - OP(PixelStorei) /* 351 */ \ - OP(PolygonOffset) /* 352 */ \ - OP(ReadPixels) /* 353 */ \ - OP(ReleaseShaderCompiler) /* 354 */ \ - OP(RenderbufferStorage) /* 355 */ \ - OP(SampleCoverage) /* 356 */ \ - OP(Scissor) /* 357 */ \ - OP(ShaderBinary) /* 358 */ \ - OP(ShaderSourceBucket) /* 359 */ \ - OP(StencilFunc) /* 360 */ \ - OP(StencilFuncSeparate) /* 361 */ \ - OP(StencilMask) /* 362 */ \ - OP(StencilMaskSeparate) /* 363 */ \ - OP(StencilOp) /* 364 */ \ - OP(StencilOpSeparate) /* 365 */ \ - OP(TexImage2D) /* 366 */ \ - OP(TexParameterf) /* 367 */ \ - OP(TexParameterfvImmediate) /* 368 */ \ - OP(TexParameteri) /* 369 */ \ - OP(TexParameterivImmediate) /* 370 */ \ - OP(TexStorage3D) /* 371 */ \ - OP(TexSubImage2D) /* 372 */ \ - OP(Uniform1f) /* 373 */ \ - OP(Uniform1fvImmediate) /* 374 */ \ - OP(Uniform1i) /* 375 */ \ - OP(Uniform1ivImmediate) /* 376 */ \ - OP(Uniform1ui) /* 377 */ \ - OP(Uniform1uivImmediate) /* 378 */ \ - OP(Uniform2f) /* 379 */ \ - OP(Uniform2fvImmediate) /* 380 */ \ - OP(Uniform2i) /* 381 */ \ - OP(Uniform2ivImmediate) /* 382 */ \ - OP(Uniform2ui) /* 383 */ \ - OP(Uniform2uivImmediate) /* 384 */ \ - OP(Uniform3f) /* 385 */ \ - OP(Uniform3fvImmediate) /* 386 */ \ - OP(Uniform3i) /* 387 */ \ - OP(Uniform3ivImmediate) /* 388 */ \ - OP(Uniform3ui) /* 389 */ \ - OP(Uniform3uivImmediate) /* 390 */ \ - OP(Uniform4f) /* 391 */ \ - OP(Uniform4fvImmediate) /* 392 */ \ - OP(Uniform4i) /* 393 */ \ - OP(Uniform4ivImmediate) /* 394 */ \ - OP(Uniform4ui) /* 395 */ \ - OP(Uniform4uivImmediate) /* 396 */ \ - OP(UniformMatrix2fvImmediate) /* 397 */ \ - OP(UniformMatrix2x3fvImmediate) /* 398 */ \ - OP(UniformMatrix2x4fvImmediate) /* 399 */ \ - OP(UniformMatrix3fvImmediate) /* 400 */ \ - OP(UniformMatrix3x2fvImmediate) /* 401 */ \ - OP(UniformMatrix3x4fvImmediate) /* 402 */ \ - OP(UniformMatrix4fvImmediate) /* 403 */ \ - OP(UniformMatrix4x2fvImmediate) /* 404 */ \ - OP(UniformMatrix4x3fvImmediate) /* 405 */ \ - OP(UseProgram) /* 406 */ \ - OP(ValidateProgram) /* 407 */ \ - OP(VertexAttrib1f) /* 408 */ \ - OP(VertexAttrib1fvImmediate) /* 409 */ \ - OP(VertexAttrib2f) /* 410 */ \ - OP(VertexAttrib2fvImmediate) /* 411 */ \ - OP(VertexAttrib3f) /* 412 */ \ - OP(VertexAttrib3fvImmediate) /* 413 */ \ - OP(VertexAttrib4f) /* 414 */ \ - OP(VertexAttrib4fvImmediate) /* 415 */ \ - OP(VertexAttribI4i) /* 416 */ \ - OP(VertexAttribI4ivImmediate) /* 417 */ \ - OP(VertexAttribI4ui) /* 418 */ \ - OP(VertexAttribI4uivImmediate) /* 419 */ \ - OP(VertexAttribIPointer) /* 420 */ \ - OP(VertexAttribPointer) /* 421 */ \ - OP(Viewport) /* 422 */ \ - OP(BlitFramebufferCHROMIUM) /* 423 */ \ - OP(RenderbufferStorageMultisampleCHROMIUM) /* 424 */ \ - OP(RenderbufferStorageMultisampleEXT) /* 425 */ \ - OP(FramebufferTexture2DMultisampleEXT) /* 426 */ \ - OP(TexStorage2DEXT) /* 427 */ \ - OP(GenQueriesEXTImmediate) /* 428 */ \ - OP(DeleteQueriesEXTImmediate) /* 429 */ \ - OP(BeginQueryEXT) /* 430 */ \ - OP(EndQueryEXT) /* 431 */ \ - OP(InsertEventMarkerEXT) /* 432 */ \ - OP(PushGroupMarkerEXT) /* 433 */ \ - OP(PopGroupMarkerEXT) /* 434 */ \ - OP(GenVertexArraysOESImmediate) /* 435 */ \ - OP(DeleteVertexArraysOESImmediate) /* 436 */ \ - OP(IsVertexArrayOES) /* 437 */ \ - OP(BindVertexArrayOES) /* 438 */ \ - OP(SwapBuffers) /* 439 */ \ - OP(GetMaxValueInBufferCHROMIUM) /* 440 */ \ - OP(EnableFeatureCHROMIUM) /* 441 */ \ - OP(ResizeCHROMIUM) /* 442 */ \ - OP(GetRequestableExtensionsCHROMIUM) /* 443 */ \ - OP(RequestExtensionCHROMIUM) /* 444 */ \ - OP(GetProgramInfoCHROMIUM) /* 445 */ \ - OP(GetTranslatedShaderSourceANGLE) /* 446 */ \ - OP(PostSubBufferCHROMIUM) /* 447 */ \ - OP(TexImageIOSurface2DCHROMIUM) /* 448 */ \ - OP(CopyTextureCHROMIUM) /* 449 */ \ - OP(DrawArraysInstancedANGLE) /* 450 */ \ - OP(DrawElementsInstancedANGLE) /* 451 */ \ - OP(VertexAttribDivisorANGLE) /* 452 */ \ - OP(GenMailboxCHROMIUM) /* 453 */ \ - OP(ProduceTextureCHROMIUMImmediate) /* 454 */ \ - OP(ProduceTextureDirectCHROMIUMImmediate) /* 455 */ \ - OP(ConsumeTextureCHROMIUMImmediate) /* 456 */ \ - OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 457 */ \ - OP(BindUniformLocationCHROMIUMBucket) /* 458 */ \ - OP(GenValuebuffersCHROMIUMImmediate) /* 459 */ \ - OP(DeleteValuebuffersCHROMIUMImmediate) /* 460 */ \ - OP(IsValuebufferCHROMIUM) /* 461 */ \ - OP(BindValuebufferCHROMIUM) /* 462 */ \ - OP(SubscribeValueCHROMIUM) /* 463 */ \ - OP(PopulateSubscribedValuesCHROMIUM) /* 464 */ \ - OP(UniformValuebufferCHROMIUM) /* 465 */ \ - OP(BindTexImage2DCHROMIUM) /* 466 */ \ - OP(ReleaseTexImage2DCHROMIUM) /* 467 */ \ - OP(TraceBeginCHROMIUM) /* 468 */ \ - OP(TraceEndCHROMIUM) /* 469 */ \ - OP(AsyncTexSubImage2DCHROMIUM) /* 470 */ \ - OP(AsyncTexImage2DCHROMIUM) /* 471 */ \ - OP(WaitAsyncTexImage2DCHROMIUM) /* 472 */ \ - OP(WaitAllAsyncTexImage2DCHROMIUM) /* 473 */ \ - OP(DiscardFramebufferEXTImmediate) /* 474 */ \ - OP(LoseContextCHROMIUM) /* 475 */ \ - OP(InsertSyncPointCHROMIUM) /* 476 */ \ - OP(WaitSyncPointCHROMIUM) /* 477 */ \ - OP(DrawBuffersEXTImmediate) /* 478 */ \ - OP(DiscardBackbufferCHROMIUM) /* 479 */ \ - OP(ScheduleOverlayPlaneCHROMIUM) /* 480 */ \ - OP(MatrixLoadfCHROMIUMImmediate) /* 481 */ \ - OP(MatrixLoadIdentityCHROMIUM) /* 482 */ \ - OP(BlendBarrierKHR) /* 483 */ + OP(InvalidateFramebufferImmediate) /* 342 */ \ + OP(InvalidateSubFramebufferImmediate) /* 343 */ \ + OP(IsBuffer) /* 344 */ \ + OP(IsEnabled) /* 345 */ \ + OP(IsFramebuffer) /* 346 */ \ + OP(IsProgram) /* 347 */ \ + OP(IsRenderbuffer) /* 348 */ \ + OP(IsShader) /* 349 */ \ + OP(IsTexture) /* 350 */ \ + OP(LineWidth) /* 351 */ \ + OP(LinkProgram) /* 352 */ \ + OP(PixelStorei) /* 353 */ \ + OP(PolygonOffset) /* 354 */ \ + OP(ReadBuffer) /* 355 */ \ + OP(ReadPixels) /* 356 */ \ + OP(ReleaseShaderCompiler) /* 357 */ \ + OP(RenderbufferStorage) /* 358 */ \ + OP(SampleCoverage) /* 359 */ \ + OP(Scissor) /* 360 */ \ + OP(ShaderBinary) /* 361 */ \ + OP(ShaderSourceBucket) /* 362 */ \ + OP(StencilFunc) /* 363 */ \ + OP(StencilFuncSeparate) /* 364 */ \ + OP(StencilMask) /* 365 */ \ + OP(StencilMaskSeparate) /* 366 */ \ + OP(StencilOp) /* 367 */ \ + OP(StencilOpSeparate) /* 368 */ \ + OP(TexImage2D) /* 369 */ \ + OP(TexParameterf) /* 370 */ \ + OP(TexParameterfvImmediate) /* 371 */ \ + OP(TexParameteri) /* 372 */ \ + OP(TexParameterivImmediate) /* 373 */ \ + OP(TexStorage3D) /* 374 */ \ + OP(TexSubImage2D) /* 375 */ \ + OP(Uniform1f) /* 376 */ \ + OP(Uniform1fvImmediate) /* 377 */ \ + OP(Uniform1i) /* 378 */ \ + OP(Uniform1ivImmediate) /* 379 */ \ + OP(Uniform1ui) /* 380 */ \ + OP(Uniform1uivImmediate) /* 381 */ \ + OP(Uniform2f) /* 382 */ \ + OP(Uniform2fvImmediate) /* 383 */ \ + OP(Uniform2i) /* 384 */ \ + OP(Uniform2ivImmediate) /* 385 */ \ + OP(Uniform2ui) /* 386 */ \ + OP(Uniform2uivImmediate) /* 387 */ \ + OP(Uniform3f) /* 388 */ \ + OP(Uniform3fvImmediate) /* 389 */ \ + OP(Uniform3i) /* 390 */ \ + OP(Uniform3ivImmediate) /* 391 */ \ + OP(Uniform3ui) /* 392 */ \ + OP(Uniform3uivImmediate) /* 393 */ \ + OP(Uniform4f) /* 394 */ \ + OP(Uniform4fvImmediate) /* 395 */ \ + OP(Uniform4i) /* 396 */ \ + OP(Uniform4ivImmediate) /* 397 */ \ + OP(Uniform4ui) /* 398 */ \ + OP(Uniform4uivImmediate) /* 399 */ \ + OP(UniformMatrix2fvImmediate) /* 400 */ \ + OP(UniformMatrix2x3fvImmediate) /* 401 */ \ + OP(UniformMatrix2x4fvImmediate) /* 402 */ \ + OP(UniformMatrix3fvImmediate) /* 403 */ \ + OP(UniformMatrix3x2fvImmediate) /* 404 */ \ + OP(UniformMatrix3x4fvImmediate) /* 405 */ \ + OP(UniformMatrix4fvImmediate) /* 406 */ \ + OP(UniformMatrix4x2fvImmediate) /* 407 */ \ + OP(UniformMatrix4x3fvImmediate) /* 408 */ \ + OP(UseProgram) /* 409 */ \ + OP(ValidateProgram) /* 410 */ \ + OP(VertexAttrib1f) /* 411 */ \ + OP(VertexAttrib1fvImmediate) /* 412 */ \ + OP(VertexAttrib2f) /* 413 */ \ + OP(VertexAttrib2fvImmediate) /* 414 */ \ + OP(VertexAttrib3f) /* 415 */ \ + OP(VertexAttrib3fvImmediate) /* 416 */ \ + OP(VertexAttrib4f) /* 417 */ \ + OP(VertexAttrib4fvImmediate) /* 418 */ \ + OP(VertexAttribI4i) /* 419 */ \ + OP(VertexAttribI4ivImmediate) /* 420 */ \ + OP(VertexAttribI4ui) /* 421 */ \ + OP(VertexAttribI4uivImmediate) /* 422 */ \ + OP(VertexAttribIPointer) /* 423 */ \ + OP(VertexAttribPointer) /* 424 */ \ + OP(Viewport) /* 425 */ \ + OP(BlitFramebufferCHROMIUM) /* 426 */ \ + OP(RenderbufferStorageMultisampleCHROMIUM) /* 427 */ \ + OP(RenderbufferStorageMultisampleEXT) /* 428 */ \ + OP(FramebufferTexture2DMultisampleEXT) /* 429 */ \ + OP(TexStorage2DEXT) /* 430 */ \ + OP(GenQueriesEXTImmediate) /* 431 */ \ + OP(DeleteQueriesEXTImmediate) /* 432 */ \ + OP(BeginQueryEXT) /* 433 */ \ + OP(EndQueryEXT) /* 434 */ \ + OP(InsertEventMarkerEXT) /* 435 */ \ + OP(PushGroupMarkerEXT) /* 436 */ \ + OP(PopGroupMarkerEXT) /* 437 */ \ + OP(GenVertexArraysOESImmediate) /* 438 */ \ + OP(DeleteVertexArraysOESImmediate) /* 439 */ \ + OP(IsVertexArrayOES) /* 440 */ \ + OP(BindVertexArrayOES) /* 441 */ \ + OP(SwapBuffers) /* 442 */ \ + OP(GetMaxValueInBufferCHROMIUM) /* 443 */ \ + OP(EnableFeatureCHROMIUM) /* 444 */ \ + OP(ResizeCHROMIUM) /* 445 */ \ + OP(GetRequestableExtensionsCHROMIUM) /* 446 */ \ + OP(RequestExtensionCHROMIUM) /* 447 */ \ + OP(GetProgramInfoCHROMIUM) /* 448 */ \ + OP(GetTranslatedShaderSourceANGLE) /* 449 */ \ + OP(PostSubBufferCHROMIUM) /* 450 */ \ + OP(TexImageIOSurface2DCHROMIUM) /* 451 */ \ + OP(CopyTextureCHROMIUM) /* 452 */ \ + OP(DrawArraysInstancedANGLE) /* 453 */ \ + OP(DrawElementsInstancedANGLE) /* 454 */ \ + OP(VertexAttribDivisorANGLE) /* 455 */ \ + OP(GenMailboxCHROMIUM) /* 456 */ \ + OP(ProduceTextureCHROMIUMImmediate) /* 457 */ \ + OP(ProduceTextureDirectCHROMIUMImmediate) /* 458 */ \ + OP(ConsumeTextureCHROMIUMImmediate) /* 459 */ \ + OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 460 */ \ + OP(BindUniformLocationCHROMIUMBucket) /* 461 */ \ + OP(GenValuebuffersCHROMIUMImmediate) /* 462 */ \ + OP(DeleteValuebuffersCHROMIUMImmediate) /* 463 */ \ + OP(IsValuebufferCHROMIUM) /* 464 */ \ + OP(BindValuebufferCHROMIUM) /* 465 */ \ + OP(SubscribeValueCHROMIUM) /* 466 */ \ + OP(PopulateSubscribedValuesCHROMIUM) /* 467 */ \ + OP(UniformValuebufferCHROMIUM) /* 468 */ \ + OP(BindTexImage2DCHROMIUM) /* 469 */ \ + OP(ReleaseTexImage2DCHROMIUM) /* 470 */ \ + OP(TraceBeginCHROMIUM) /* 471 */ \ + OP(TraceEndCHROMIUM) /* 472 */ \ + OP(AsyncTexSubImage2DCHROMIUM) /* 473 */ \ + OP(AsyncTexImage2DCHROMIUM) /* 474 */ \ + OP(WaitAsyncTexImage2DCHROMIUM) /* 475 */ \ + OP(WaitAllAsyncTexImage2DCHROMIUM) /* 476 */ \ + OP(DiscardFramebufferEXTImmediate) /* 477 */ \ + OP(LoseContextCHROMIUM) /* 478 */ \ + OP(InsertSyncPointCHROMIUM) /* 479 */ \ + OP(WaitSyncPointCHROMIUM) /* 480 */ \ + OP(DrawBuffersEXTImmediate) /* 481 */ \ + OP(DiscardBackbufferCHROMIUM) /* 482 */ \ + OP(ScheduleOverlayPlaneCHROMIUM) /* 483 */ \ + OP(MatrixLoadfCHROMIUMImmediate) /* 484 */ \ + OP(MatrixLoadIdentityCHROMIUM) /* 485 */ \ + OP(BlendBarrierKHR) /* 486 */ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 9fec2e1..a15c791 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -139,7 +139,6 @@ map_buffer_range(false), ext_discard_framebuffer(false), angle_depth_texture(false), - is_angle(false), is_swiftshader(false), angle_texture_usage(false), ext_texture_storage(false), @@ -271,17 +270,10 @@ const char* renderer_str = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); - if (renderer_str) { - feature_flags_.is_angle = StartsWithASCII(renderer_str, "ANGLE", true); - } - - bool is_es3 = false; const char* version_str = reinterpret_cast<const char*>(glGetString(GL_VERSION)); - if (version_str) { - std::string lstr(base::StringToLowerASCII(std::string(version_str))); - is_es3 = (lstr.substr(0, 12) == "opengl es 3."); - } + + gl_version_info_.reset(new gfx::GLVersionInfo(version_str, renderer_str)); AddExtensionString("GL_ANGLE_translated_shader_source"); AddExtensionString("GL_CHROMIUM_async_pixel_transfers"); @@ -386,7 +378,8 @@ if (!workarounds_.disable_depth_texture && (extensions.Contains("GL_ARB_depth_texture") || extensions.Contains("GL_OES_depth_texture") || - extensions.Contains("GL_ANGLE_depth_texture") || is_es3)) { + extensions.Contains("GL_ANGLE_depth_texture") || + gl_version_info_->is_es3)) { enable_depth_texture = true; feature_flags_.angle_depth_texture = extensions.Contains("GL_ANGLE_depth_texture"); @@ -404,7 +397,8 @@ } if (extensions.Contains("GL_EXT_packed_depth_stencil") || - extensions.Contains("GL_OES_packed_depth_stencil") || is_es3) { + extensions.Contains("GL_OES_packed_depth_stencil") || + gl_version_info_->is_es3) { AddExtensionString("GL_OES_packed_depth_stencil"); feature_flags_.packed_depth24_stencil8 = true; if (enable_depth_texture) { @@ -417,7 +411,8 @@ validators_.render_buffer_format.AddValue(GL_DEPTH24_STENCIL8); } - if (is_es3 || extensions.Contains("GL_OES_vertex_array_object") || + if (gl_version_info_->is_es3 || + extensions.Contains("GL_OES_vertex_array_object") || extensions.Contains("GL_ARB_vertex_array_object") || extensions.Contains("GL_APPLE_vertex_array_object")) { feature_flags_.native_vertex_array_object = true; @@ -430,7 +425,8 @@ feature_flags_.native_vertex_array_object = false; } - if (is_es3 || extensions.Contains("GL_OES_element_index_uint") || + if (gl_version_info_->is_es3 || + extensions.Contains("GL_OES_element_index_uint") || gfx::HasDesktopGLFeatures()) { AddExtensionString("GL_OES_element_index_uint"); validators_.index_type.AddValue(GL_UNSIGNED_INT); @@ -442,7 +438,8 @@ // sized formats GL_SRGB8 and GL_SRGB8_ALPHA8. Also, SRGB_EXT isn't a valid // <format> in this case. So, even with GLES3 explicitly check for // GL_EXT_sRGB. - if (((is_es3 || extensions.Contains("GL_OES_rgb8_rgba8")) && + if (((gl_version_info_->is_es3 || + extensions.Contains("GL_OES_rgb8_rgba8")) && extensions.Contains("GL_EXT_sRGB")) || gfx::HasDesktopGLFeatures()) { AddExtensionString("GL_EXT_sRGB"); texture_format_validators_[GL_SRGB_EXT].AddValue(GL_UNSIGNED_BYTE); @@ -503,7 +500,8 @@ } // Check if we should allow GL_OES_texture_npot - if (is_es3 || extensions.Contains("GL_ARB_texture_non_power_of_two") || + if (gl_version_info_->is_es3 || + extensions.Contains("GL_ARB_texture_non_power_of_two") || extensions.Contains("GL_OES_texture_npot")) { AddExtensionString("GL_OES_texture_npot"); feature_flags_.npot_ok = true; @@ -535,8 +533,9 @@ // This extension allows a variety of floating point formats to be // rendered to via framebuffer objects. Enable it's usage only if // support for Floating textures is enabled. - if ((is_es3 && extensions.Contains("GL_EXT_color_buffer_float")) || - feature_flags_.is_angle) { + if ((gl_version_info_->is_es3 && + extensions.Contains("GL_EXT_color_buffer_float")) || + gl_version_info_->is_angle) { may_enable_chromium_color_buffer_float = true; } } @@ -638,12 +637,13 @@ // Check for multisample support if (!workarounds_.disable_multisampling) { bool ext_has_multisample = - extensions.Contains("GL_EXT_framebuffer_multisample") || is_es3; - if (feature_flags_.is_angle) { + extensions.Contains("GL_EXT_framebuffer_multisample") || + gl_version_info_->is_es3; + if (gl_version_info_->is_angle) { ext_has_multisample |= extensions.Contains("GL_ANGLE_framebuffer_multisample"); } - feature_flags_.use_core_framebuffer_multisample = is_es3; + feature_flags_.use_core_framebuffer_multisample = gl_version_info_->is_es3; if (ext_has_multisample) { feature_flags_.chromium_framebuffer_multisample = true; validators_.frame_buffer_target.AddValue(GL_READ_FRAMEBUFFER_EXT); @@ -670,14 +670,15 @@ } if (extensions.Contains("GL_OES_depth24") || gfx::HasDesktopGLFeatures() || - is_es3) { + gl_version_info_->is_es3) { AddExtensionString("GL_OES_depth24"); feature_flags_.oes_depth24 = true; validators_.render_buffer_format.AddValue(GL_DEPTH_COMPONENT24); } if (!workarounds_.disable_oes_standard_derivatives && - (is_es3 || extensions.Contains("GL_OES_standard_derivatives") || + (gl_version_info_->is_es3 || + extensions.Contains("GL_OES_standard_derivatives") || gfx::HasDesktopGLFeatures())) { AddExtensionString("GL_OES_standard_derivatives"); feature_flags_.oes_standard_derivatives = true; @@ -771,8 +772,10 @@ // However we expose GL_EXT_texture_storage when just ES3 because we don't // claim to handle GL_BGRA8. bool support_texture_storage_on_es3 = - (is_es3 && enable_immutable_texture_format_bgra_on_es3) || - (is_es3 && !enable_texture_format_bgra8888); + (gl_version_info_->is_es3 && + enable_immutable_texture_format_bgra_on_es3) || + (gl_version_info_->is_es3 && + !enable_texture_format_bgra8888); if (extensions.Contains("GL_EXT_texture_storage") || extensions.Contains("GL_ARB_texture_storage") || support_texture_storage_on_es3) { @@ -825,7 +828,7 @@ (extensions.Contains("GL_ANGLE_instanced_arrays") || (extensions.Contains("GL_ARB_instanced_arrays") && extensions.Contains("GL_ARB_draw_instanced")) || - is_es3)) { + gl_version_info_->is_es3)) { AddExtensionString("GL_ANGLE_instanced_arrays"); feature_flags_.angle_instanced_arrays = true; validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); @@ -836,7 +839,8 @@ extensions.Contains("GL_EXT_draw_buffers"); if (!workarounds_.disable_ext_draw_buffers && (vendor_agnostic_draw_buffers || - (extensions.Contains("GL_NV_draw_buffers") && is_es3))) { + (extensions.Contains("GL_NV_draw_buffers") && + gl_version_info_->is_es3))) { AddExtensionString("GL_EXT_draw_buffers"); feature_flags_.ext_draw_buffers = true; @@ -871,7 +875,8 @@ } } - if (is_es3 || extensions.Contains("GL_EXT_blend_minmax") || + if (gl_version_info_->is_es3 || + extensions.Contains("GL_EXT_blend_minmax") || gfx::HasDesktopGLFeatures()) { AddExtensionString("GL_EXT_blend_minmax"); validators_.equation.AddValue(GL_MIN_EXT); @@ -906,13 +911,15 @@ UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works); feature_flags_.map_buffer_range = - is_es3 || extensions.Contains("GL_ARB_map_buffer_range") || + gl_version_info_->is_es3 || + extensions.Contains("GL_ARB_map_buffer_range") || extensions.Contains("GL_EXT_map_buffer_range"); // Really it's part of core OpenGL 2.1 and up, but let's assume the // extension is still advertised. bool has_pixel_buffers = - is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object") || + gl_version_info_->is_es3 || + extensions.Contains("GL_ARB_pixel_buffer_object") || extensions.Contains("GL_NV_pixel_buffer_object"); // We will use either glMapBuffer() or glMapBufferRange() for async readbacks. @@ -921,13 +928,15 @@ feature_flags_.use_async_readpixels = true; } - if (is_es3 || extensions.Contains("GL_ARB_sampler_objects")) { + if (gl_version_info_->is_es3 || + extensions.Contains("GL_ARB_sampler_objects")) { feature_flags_.enable_samplers = true; // TODO(dsinclair): Add AddExtensionString("GL_CHROMIUM_sampler_objects") // when available. } - if ((is_es3 || extensions.Contains("GL_EXT_discard_framebuffer")) && + if ((gl_version_info_->is_es3 || + extensions.Contains("GL_EXT_discard_framebuffer")) && !workarounds_.disable_ext_discard_framebuffer) { // DiscardFramebufferEXT is automatically bound to InvalidateFramebuffer. AddExtensionString("GL_EXT_discard_framebuffer"); @@ -974,7 +983,8 @@ } if (extensions.Contains("GL_NV_path_rendering")) { - if (extensions.Contains("GL_EXT_direct_state_access") || is_es3) { + if (extensions.Contains("GL_EXT_direct_state_access") || + gl_version_info_->is_es3) { AddExtensionString("GL_CHROMIUM_path_rendering"); feature_flags_.chromium_path_rendering = true; validators_.g_l_state.AddValue(GL_PATH_MODELVIEW_MATRIX_CHROMIUM); @@ -982,7 +992,7 @@ } } - if ((is_es3 || extensions.Contains("GL_EXT_texture_rg") || + if ((gl_version_info_->is_es3 || extensions.Contains("GL_EXT_texture_rg") || extensions.Contains("GL_ARB_texture_rg")) && IsGL_REDSupportedOnFBOs()) { feature_flags_.ext_texture_rg = true;
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 816ab49..c4bf479 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h
@@ -14,6 +14,7 @@ #include "gpu/command_buffer/service/gles2_cmd_validation.h" #include "gpu/config/gpu_driver_bug_workaround_type.h" #include "gpu/gpu_export.h" +#include "ui/gl/gl_version_info.h" namespace base { class CommandLine; @@ -66,7 +67,6 @@ bool map_buffer_range; bool ext_discard_framebuffer; bool angle_depth_texture; - bool is_angle; bool is_swiftshader; bool angle_texture_usage; bool ext_texture_storage; @@ -122,6 +122,11 @@ return workarounds_; } + const gfx::GLVersionInfo& gl_version_info() const { + CHECK(gl_version_info_.get()); + return *(gl_version_info_.get()); + } + private: friend class base::RefCounted<FeatureInfo>; friend class BufferManagerClientSideArraysTest; @@ -148,6 +153,8 @@ // Flags for Workarounds. Workarounds workarounds_; + scoped_ptr<gfx::GLVersionInfo> gl_version_info_; + DISALLOW_COPY_AND_ASSIGN(FeatureInfo); };
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index b314262..06f3d11 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -127,7 +127,6 @@ EXPECT_FALSE(info_->feature_flags().nv_draw_buffers); EXPECT_FALSE(info_->feature_flags().ext_discard_framebuffer); EXPECT_FALSE(info_->feature_flags().angle_depth_texture); - EXPECT_FALSE(info_->feature_flags().is_angle); #define GPU_OP(type, name) EXPECT_FALSE(info_->workarounds().name); GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) @@ -345,7 +344,7 @@ TEST_F(FeatureInfoTest, InitializeWithANGLE) { SetupInitExpectationsWithGLVersion("", kGLRendererStringANGLE, ""); - EXPECT_TRUE(info_->feature_flags().is_angle); + EXPECT_TRUE(info_->gl_version_info().is_angle); } TEST_F(FeatureInfoTest, InitializeNPOTExtensionGLES) {
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index ffb9370..5122613 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -260,8 +260,9 @@ framebuffer_(0u) {} CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() { - DCHECK(!buffer_id_); - DCHECK(!framebuffer_); + // |buffer_id_| and |framebuffer_| can be not-null because when GPU context is + // lost, this class can be deleted without releasing resources like + // GLES2DecoderImpl. } void CopyTextureCHROMIUMResourceManager::Initialize( @@ -330,7 +331,8 @@ // format of internalformat. // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml bool source_format_contain_superset_of_dest_format = - source_internal_format == dest_internal_format || + (source_internal_format == dest_internal_format && + source_internal_format != GL_BGRA_EXT) || (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB); // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, // so restrict this to GL_TEXTURE_2D.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 422168c..919d8d8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -4494,7 +4494,13 @@ } ScopedRenderTo do_render(framebuffer); - glDiscardFramebufferEXT(target, numAttachments, translated_attachments.get()); + if (feature_info_->gl_version_info().is_es3) { + glInvalidateFramebuffer( + target, numAttachments, translated_attachments.get()); + } else { + glDiscardFramebufferEXT( + target, numAttachments, translated_attachments.get()); + } } void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) { @@ -5495,7 +5501,7 @@ GLsizei height) { // TODO(sievers): This could be resolved at the GL binding level, but the // binding process is currently a bit too 'brute force'. - if (feature_info->feature_flags().is_angle) { + if (feature_info->gl_version_info().is_angle) { glRenderbufferStorageMultisampleANGLE( target, samples, internal_format, width, height); } else if (feature_info->feature_flags().use_core_framebuffer_multisample) { @@ -5519,7 +5525,7 @@ GLenum filter) { // TODO(sievers): This could be resolved at the GL binding level, but the // binding process is currently a bit too 'brute force'. - if (feature_info_->feature_flags().is_angle) { + if (feature_info_->gl_version_info().is_angle) { glBlitFramebufferANGLE( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } else if (feature_info_->feature_flags().use_core_framebuffer_multisample) { @@ -7865,8 +7871,8 @@ glGenBuffersARB(1, &buffer); glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer); // For ANGLE client version 2, GL_STREAM_READ is not available. - const GLenum usage_hint = - features().is_angle ? GL_STATIC_DRAW : GL_STREAM_READ; + const GLenum usage_hint = feature_info_->gl_version_info().is_angle ? + GL_STATIC_DRAW : GL_STREAM_READ; glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, usage_hint); GLenum error = glGetError(); if (error == GL_NO_ERROR) { @@ -9703,7 +9709,7 @@ // Ensure the side effects of the copy are visible to the parent // context. There is no need to do this for ANGLE because it uses a // single D3D device for all contexts. - if (!feature_info_->feature_flags().is_angle) + if (!feature_info_->gl_version_info().is_angle) glFlush(); } } else {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index ebdb625..b84fc2a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -1493,6 +1493,74 @@ return error::kNoError; } +error::Error GLES2DecoderImpl::HandleInvalidateFramebufferImmediate( + uint32_t immediate_data_size, + const void* cmd_data) { + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + const gles2::cmds::InvalidateFramebufferImmediate& c = + *static_cast<const gles2::cmds::InvalidateFramebufferImmediate*>( + cmd_data); + (void)c; + GLenum target = static_cast<GLenum>(c.target); + GLsizei count = static_cast<GLsizei>(c.count); + uint32_t data_size; + if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) { + return error::kOutOfBounds; + } + if (data_size > immediate_data_size) { + return error::kOutOfBounds; + } + const GLenum* attachments = + GetImmediateDataAs<const GLenum*>(c, data_size, immediate_data_size); + if (attachments == NULL) { + return error::kOutOfBounds; + } + glInvalidateFramebuffer(target, count, attachments); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleInvalidateSubFramebufferImmediate( + uint32_t immediate_data_size, + const void* cmd_data) { + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + const gles2::cmds::InvalidateSubFramebufferImmediate& c = + *static_cast<const gles2::cmds::InvalidateSubFramebufferImmediate*>( + cmd_data); + (void)c; + GLenum target = static_cast<GLenum>(c.target); + GLsizei count = static_cast<GLsizei>(c.count); + uint32_t data_size; + if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) { + return error::kOutOfBounds; + } + if (data_size > immediate_data_size) { + return error::kOutOfBounds; + } + const GLenum* attachments = + GetImmediateDataAs<const GLenum*>(c, data_size, immediate_data_size); + GLint x = static_cast<GLint>(c.x); + GLint y = static_cast<GLint>(c.y); + GLsizei width = static_cast<GLsizei>(c.width); + GLsizei height = static_cast<GLsizei>(c.height); + if (attachments == NULL) { + return error::kOutOfBounds; + } + if (width < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", + "width < 0"); + return error::kNoError; + } + if (height < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glInvalidateSubFramebuffer", + "height < 0"); + return error::kNoError; + } + glInvalidateSubFramebuffer(target, count, attachments, x, y, width, height); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleIsBuffer(uint32_t immediate_data_size, const void* cmd_data) { const gles2::cmds::IsBuffer& c = @@ -1653,6 +1721,18 @@ return error::kNoError; } +error::Error GLES2DecoderImpl::HandleReadBuffer(uint32_t immediate_data_size, + const void* cmd_data) { + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + const gles2::cmds::ReadBuffer& c = + *static_cast<const gles2::cmds::ReadBuffer*>(cmd_data); + (void)c; + GLenum src = static_cast<GLenum>(c.src); + glReadBuffer(src); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleReleaseShaderCompiler( uint32_t immediate_data_size, const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index f9b450e..014007a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -1698,6 +1698,8 @@ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); } +// TODO(gman): InvalidateFramebufferImmediate +// TODO(gman): InvalidateSubFramebufferImmediate TEST_P(GLES2DecoderTest1, IsBufferValidArgs) { SpecializedSetup<cmds::IsBuffer, 0>(true); @@ -1875,14 +1877,4 @@ } // TODO(gman): PixelStorei -TEST_P(GLES2DecoderTest1, PolygonOffsetValidArgs) { - EXPECT_CALL(*gl_, PolygonOffset(1, 2)); - SpecializedSetup<cmds::PolygonOffset, 0>(true); - cmds::PolygonOffset cmd; - cmd.Init(1, 2); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); -} -// TODO(gman): ReadPixels - #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index b69197f..602be42 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -12,6 +12,28 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_ +TEST_P(GLES2DecoderTest2, PolygonOffsetValidArgs) { + EXPECT_CALL(*gl_, PolygonOffset(1, 2)); + SpecializedSetup<cmds::PolygonOffset, 0>(true); + cmds::PolygonOffset cmd; + cmd.Init(1, 2); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTest2, ReadBufferValidArgs) { + EXPECT_CALL(*gl_, ReadBuffer(1)); + SpecializedSetup<cmds::ReadBuffer, 0>(true); + cmds::ReadBuffer cmd; + cmd.Init(1); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + decoder_->set_unsafe_es3_apis_enabled(false); + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); +} +// TODO(gman): ReadPixels + // TODO(gman): ReleaseShaderCompiler TEST_P(GLES2DecoderTest2, RenderbufferStorageValidArgs) { @@ -1015,7 +1037,4 @@ // TODO(gman): GetTranslatedShaderSourceANGLE // TODO(gman): PostSubBufferCHROMIUM // TODO(gman): TexImageIOSurface2DCHROMIUM -// TODO(gman): CopyTextureCHROMIUM -// TODO(gman): DrawArraysInstancedANGLE -// TODO(gman): DrawElementsInstancedANGLE #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index 0ee2ba5..4509676 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,6 +12,9 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ +// TODO(gman): CopyTextureCHROMIUM +// TODO(gman): DrawArraysInstancedANGLE +// TODO(gman): DrawElementsInstancedANGLE // TODO(gman): VertexAttribDivisorANGLE // TODO(gman): GenMailboxCHROMIUM
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc index 78fa020..d230be7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -2120,7 +2120,7 @@ // EXPECT_EQ can't be used to compare function pointers EXPECT_TRUE( - gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") == + gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") != gfx::g_driver_gl.fn.glDiscardFramebufferEXTFn); EXPECT_TRUE( gfx::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") !=
diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index 48df8dd..3f8f1bf 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc
@@ -22,8 +22,6 @@ namespace gpu { -const int64 kUnscheduleFenceTimeOutDelay = 10000; - #if defined(OS_WIN) const int64 kRescheduleTimeOutDelay = 1000; #endif @@ -59,10 +57,6 @@ if (state.error != error::kNoError) return; - // Check that the GPU has passed all fences. - if (!PollUnscheduleFences()) - return; - // One of the unschedule fence tasks might have unscheduled us. if (!IsScheduled()) return; @@ -76,7 +70,6 @@ break; DCHECK(IsScheduled()); - DCHECK(unschedule_fences_.empty()); error = parser_->ProcessCommands(CommandParser::kParseCommandsSlice); @@ -169,8 +162,7 @@ } bool GpuScheduler::HasMoreWork() { - return !unschedule_fences_.empty() || - (decoder_ && decoder_->ProcessPendingQueries(false)) || + return (decoder_ && decoder_->ProcessPendingQueries(false)) || HasMoreIdleWork(); } @@ -222,45 +214,6 @@ command_processed_callback_ = callback; } -void GpuScheduler::DeferToFence(base::Closure task) { - unschedule_fences_.push(make_linked_ptr( - new UnscheduleFence(gfx::GLFence::Create(), task))); - SetScheduled(false); -} - -bool GpuScheduler::PollUnscheduleFences() { - if (unschedule_fences_.empty()) - return true; - - if (unschedule_fences_.front()->fence.get()) { - base::Time now = base::Time::Now(); - base::TimeDelta timeout = - base::TimeDelta::FromMilliseconds(kUnscheduleFenceTimeOutDelay); - - while (!unschedule_fences_.empty()) { - const UnscheduleFence& fence = *unschedule_fences_.front(); - if (fence.fence->HasCompleted() || - now - fence.issue_time > timeout) { - unschedule_fences_.front()->task.Run(); - unschedule_fences_.pop(); - SetScheduled(true); - } else { - return false; - } - } - } else { - glFinish(); - - while (!unschedule_fences_.empty()) { - unschedule_fences_.front()->task.Run(); - unschedule_fences_.pop(); - SetScheduled(true); - } - } - - return true; -} - bool GpuScheduler::IsPreempted() { if (!preemption_flag_.get()) return false; @@ -297,14 +250,4 @@ rescheduled_count_ = new_count; } -GpuScheduler::UnscheduleFence::UnscheduleFence(gfx::GLFence* fence_, - base::Closure task_) - : fence(fence_), - issue_time(base::Time::Now()), - task(task_) { -} - -GpuScheduler::UnscheduleFence::~UnscheduleFence() { -} - } // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_scheduler.h b/gpu/command_buffer/service/gpu_scheduler.h index 5e47d4a..b0b2630 100644 --- a/gpu/command_buffer/service/gpu_scheduler.h +++ b/gpu/command_buffer/service/gpu_scheduler.h
@@ -91,12 +91,6 @@ void SetCommandProcessedCallback(const base::Closure& callback); - void DeferToFence(base::Closure task); - - // Polls the fences, invoking callbacks that were waiting to be triggered - // by them and returns whether all fences were complete. - bool PollUnscheduleFences(); - bool HasMoreIdleWork(); void PerformIdleWork(); @@ -136,18 +130,6 @@ // account of a timeout. int rescheduled_count_; - // The GpuScheduler will unschedule itself in the event that further GL calls - // are issued to it before all these fences have been crossed by the GPU. - struct UnscheduleFence { - UnscheduleFence(gfx::GLFence* fence, base::Closure task); - ~UnscheduleFence(); - - scoped_ptr<gfx::GLFence> fence; - base::Time issue_time; - base::Closure task; - }; - std::queue<linked_ptr<UnscheduleFence> > unschedule_fences_; - SchedulingChangedCallback scheduling_changed_callback_; base::Closure descheduled_callback_; base::Closure command_processed_callback_;
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index 7d9fb6f..7e9f7bd 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -440,7 +440,7 @@ EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[1])) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, width, width, 0, + EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, _, width, width, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, _)) .Times(1) .RetiresOnSaturation();
diff --git a/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py b/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py index 3147286..2b4705b 100755 --- a/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py +++ b/gpu/khronos_glcts_support/generate_khronos_glcts_tests.py
@@ -20,6 +20,18 @@ "mustpass_es20.run" : "ES2-CTS.gtf", } +BUILT_IN_TESTS = { + "mustpass_es20.run" : [ + "CTS-Configs.es2", + "ES2-CTS.info.vendor", + "ES2-CTS.info.renderer", + "ES2-CTS.info.version", + "ES2-CTS.info.shading_language_version", + "ES2-CTS.info.extensions", + "ES2-CTS.info.render_target", + ], +} + def ReadFileAsLines(filename): """ Reads a file, yielding each non-blank line @@ -64,6 +76,13 @@ run_file_dir = os.path.dirname(run_file) suite_prefix = RUN_FILE_SUITE_PREFIX[run_file_name] output.write("// " + run_file_name + "\n") + builtin_tests = BUILT_IN_TESTS[run_file_name] + for test in builtin_tests: + output.write(TEST_DEF_TEMPLATE + % { + "gname": re.sub(r'[^A-Za-z0-9]', '_', test), + "cname": test, + }) for test in ReadRunFile(run_file): rel_path = os.path.relpath(test, run_file_dir) root, ext = os.path.splitext(rel_path)
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc index 841f454..f746f9b 100644 --- a/net/base/directory_lister.cc +++ b/net/base/directory_lister.cc
@@ -5,12 +5,12 @@ #include "net/base/directory_lister.h" #include <algorithm> -#include <vector> #include "base/bind.h" #include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/i18n/file_util_icu.h" +#include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" @@ -73,22 +73,23 @@ DirectoryLister::SortType sort_type) { // Sort the results. See the TODO below (this sort should be removed and we // should do it from JS). - if (sort_type == DirectoryLister::DATE) + if (sort_type == DirectoryLister::DATE) { std::sort(data->begin(), data->end(), CompareDate); - else if (sort_type == DirectoryLister::FULL_PATH) + } else if (sort_type == DirectoryLister::FULL_PATH) { std::sort(data->begin(), data->end(), CompareFullPath); - else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST) + } else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST) { std::sort(data->begin(), data->end(), CompareAlphaDirsFirst); - else + } else { DCHECK_EQ(DirectoryLister::NO_SORT, sort_type); + } } } // namespace DirectoryLister::DirectoryLister(const base::FilePath& dir, DirectoryListerDelegate* delegate) - : core_(new Core(dir, false, ALPHA_DIRS_FIRST, this)), - delegate_(delegate) { + : delegate_(delegate) { + core_ = new Core(dir, false, ALPHA_DIRS_FIRST, this); DCHECK(delegate_); DCHECK(!dir.value().empty()); } @@ -97,8 +98,8 @@ bool recursive, SortType sort, DirectoryListerDelegate* delegate) - : core_(new Core(dir, recursive, sort, this)), - delegate_(delegate) { + : delegate_(delegate) { + core_ = new Core(dir, recursive, sort, this); DCHECK(delegate_); DCHECK(!dir.value().empty()); } @@ -108,11 +109,14 @@ } bool DirectoryLister::Start() { - return core_->Start(); + return base::WorkerPool::PostTask( + FROM_HERE, + base::Bind(&Core::Start, core_), + true); } void DirectoryLister::Cancel() { - return core_->Cancel(); + core_->CancelOnOriginThread(); } DirectoryLister::Core::Core(const base::FilePath& dir, @@ -122,29 +126,32 @@ : dir_(dir), recursive_(recursive), sort_(sort), - lister_(lister) { + origin_loop_(base::MessageLoopProxy::current()), + lister_(lister), + cancelled_(0) { DCHECK(lister_); } DirectoryLister::Core::~Core() {} -bool DirectoryLister::Core::Start() { - origin_loop_ = base::MessageLoopProxy::current(); +void DirectoryLister::Core::CancelOnOriginThread() { + DCHECK(origin_loop_->BelongsToCurrentThread()); - return base::WorkerPool::PostTask( - FROM_HERE, base::Bind(&Core::StartInternal, this), true); + base::subtle::NoBarrier_Store(&cancelled_, 1); + // Core must not call into |lister_| after cancellation, as the |lister_| may + // have been destroyed. Setting |lister_| to NULL ensures any such access will + // cause a crash. + lister_ = nullptr; } -void DirectoryLister::Core::Cancel() { - lister_ = NULL; -} - -void DirectoryLister::Core::StartInternal() { +void DirectoryLister::Core::Start() { + scoped_ptr<DirectoryList> directory_list(new DirectoryList()); if (!base::DirectoryExists(dir_)) { origin_loop_->PostTask( FROM_HERE, - base::Bind(&DirectoryLister::Core::OnDone, this, ERR_FILE_NOT_FOUND)); + base::Bind(&Core::DoneOnOriginThread, this, + base::Passed(directory_list.Pass()), ERR_FILE_NOT_FOUND)); return; } @@ -155,12 +162,16 @@ base::FileEnumerator file_enum(dir_, recursive_, types); base::FilePath path; - std::vector<DirectoryListerData> file_data; - while (lister_ && !(path = file_enum.Next()).empty()) { + while (!(path = file_enum.Next()).empty()) { + // Abort on cancellation. This is purely for performance reasons. + // Correctness guarantees are made by checks in DoneOnOriginThread. + if (IsCancelled()) + return; + DirectoryListerData data; data.info = file_enum.GetInfo(); data.path = path; - file_data.push_back(data); + directory_list->push_back(data); /* TODO(brettw) bug 24107: It would be nice to send incremental updates. We gather them all so they can be sorted, but eventually the sorting @@ -178,36 +189,40 @@ */ } - SortData(&file_data, sort_); - origin_loop_->PostTask( - FROM_HERE, - base::Bind(&DirectoryLister::Core::SendData, this, file_data)); + SortData(directory_list.get(), sort_); origin_loop_->PostTask( FROM_HERE, - base::Bind(&DirectoryLister::Core::OnDone, this, OK)); + base::Bind(&Core::DoneOnOriginThread, this, + base::Passed(directory_list.Pass()), OK)); } -void DirectoryLister::Core::SendData( - const std::vector<DirectoryLister::DirectoryListerData>& data) { +bool DirectoryLister::Core::IsCancelled() const { + return !!base::subtle::NoBarrier_Load(&cancelled_); +} + +void DirectoryLister::Core::DoneOnOriginThread( + scoped_ptr<DirectoryList> directory_list, int error) const { DCHECK(origin_loop_->BelongsToCurrentThread()); - // We need to check for cancellation (indicated by NULL'ing of |lister_|) - // which can happen during each callback. - for (size_t i = 0; lister_ && i < data.size(); ++i) - lister_->OnReceivedData(data[i]); + + // Need to check if the operation was before first callback. + if (IsCancelled()) + return; + + for (const auto& lister_data : *directory_list) { + lister_->OnListFile(lister_data); + // Need to check if the operation was cancelled during the callback. + if (IsCancelled()) + return; + } + lister_->OnListDone(error); } -void DirectoryLister::Core::OnDone(int error) { - DCHECK(origin_loop_->BelongsToCurrentThread()); - if (lister_) - lister_->OnDone(error); -} - -void DirectoryLister::OnReceivedData(const DirectoryListerData& data) { +void DirectoryLister::OnListFile(const DirectoryListerData& data) { delegate_->OnListFile(data); } -void DirectoryLister::OnDone(int error) { +void DirectoryLister::OnListDone(int error) { delegate_->OnListDone(error); }
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h index 5fbc9dc..51387e8 100644 --- a/net/base/directory_lister.h +++ b/net/base/directory_lister.h
@@ -7,21 +7,22 @@ #include <vector> +#include "base/atomicops.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" +#include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "net/base/net_export.h" namespace net { -// -// This class provides an API for listing the contents of a directory on the -// filesystem asynchronously. It spawns a background thread, and enumerates -// the specified directory on that thread. It marshalls WIN32_FIND_DATA -// structs over to the main application thread. The consumer of this class -// is insulated from any of the multi-threading details. -// +// This class provides an API for asynchronously listing the contents of a +// directory on the filesystem. It runs a task on a background thread, and +// enumerates all files in the specified directory on that thread. Destroying +// the lister cancels the list operation. The DirectoryLister must only be +// used on a thread with a MessageLoop. class NET_EXPORT DirectoryLister { public: // Represents one file found. @@ -48,6 +49,9 @@ // directories first in name order, then files by name order // FULL_PATH sorts by paths as strings, ignoring files v. directories // DATE sorts by last modified date + // TODO(mmenke): Only NO_SORT and ALPHA_DIRS_FIRST appear to be used in + // production code, and there's very little testing of some of these + // options. Remove unused options, improve testing of the others. enum SortType { NO_SORT, DATE, @@ -74,6 +78,15 @@ void Cancel(); private: + typedef std::vector<DirectoryListerData> DirectoryList; + + // Class responsible for retrieving and sorting the actual directory list on + // a worker pool thread. Created on the DirectoryLister's thread. As it's + // refcounted, it's destroyed when the final reference is released, which may + // happen on either thread. + // + // It's kept alive during the calls to Start() and DoneOnOriginThread() by the + // reference owned by the callback itself. class Core : public base::RefCountedThreadSafe<Core> { public: Core(const base::FilePath& dir, @@ -81,9 +94,11 @@ SortType sort, DirectoryLister* lister); - bool Start(); + // May only be called on a worker pool thread. + void Start(); - void Cancel(); + // Must be called on the origin thread. + void CancelOnOriginThread(); private: friend class base::RefCountedThreadSafe<Core>; @@ -91,28 +106,35 @@ ~Core(); - // This method runs on a WorkerPool thread. - void StartInternal(); + // Called on both threads. + bool IsCancelled() const; - void SendData(const std::vector<DirectoryListerData>& data); + // Called on origin thread. + void DoneOnOriginThread(scoped_ptr<DirectoryList> directory_list, + int error) const; - void OnDone(int error); + const base::FilePath dir_; + const bool recursive_; + const SortType sort_; + const scoped_refptr<base::MessageLoopProxy> origin_loop_; - base::FilePath dir_; - bool recursive_; - SortType sort_; - scoped_refptr<base::MessageLoopProxy> origin_loop_; - - // |lister_| gets set to NULL when canceled. + // Only used on the origin thread. DirectoryLister* lister_; + // Set to 1 on cancellation. Used both to abort listing files early on the + // worker pool thread for performance reasons and to ensure |lister_| isn't + // called after cancellation on the origin thread. + base::subtle::Atomic32 cancelled_; + DISALLOW_COPY_AND_ASSIGN(Core); }; - void OnReceivedData(const DirectoryListerData& data); - void OnDone(int error); + // Call into the corresponding DirectoryListerDelegate. Must not be called + // after cancellation. + void OnListFile(const DirectoryListerData& data); + void OnListDone(int error); - const scoped_refptr<Core> core_; + scoped_refptr<Core> core_; DirectoryListerDelegate* const delegate_; DISALLOW_COPY_AND_ASSIGN(DirectoryLister);
diff --git a/net/base/directory_lister_unittest.cc b/net/base/directory_lister_unittest.cc index 869e4f6..adc3d5e 100644 --- a/net/base/directory_lister_unittest.cc +++ b/net/base/directory_lister_unittest.cc
@@ -4,12 +4,15 @@ #include <list> #include <utility> +#include <vector> +#include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/i18n/file_util_icu.h" #include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "net/base/directory_lister.h" #include "net/base/net_errors.h" @@ -18,29 +21,59 @@ namespace net { +namespace { + +const int kMaxDepth = 3; +const int kBranchingFactor = 4; +const int kFilesPerDirectory = 5; + class ListerDelegate : public DirectoryLister::DirectoryListerDelegate { public: - ListerDelegate(bool recursive, - bool quit_loop_after_each_file) - : error_(-1), - recursive_(recursive), - quit_loop_after_each_file_(quit_loop_after_each_file) { + explicit ListerDelegate(bool recursive) + : cancel_lister_on_list_file_(false), + cancel_lister_on_list_done_(false), + lister_(nullptr), + done_(false), + error_(-1), + recursive_(recursive) { + } + + // When set to true, this signals that the directory list operation should be + // cancelled (And the run loop quit) in the first call to OnListFile. + void set_cancel_lister_on_list_file(bool cancel_lister_on_list_file) { + cancel_lister_on_list_file_ = cancel_lister_on_list_file; + } + + // When set to true, this signals that the directory list operation should be + // cancelled (And the run loop quit) when OnDone is called. + void set_cancel_lister_on_list_done(bool cancel_lister_on_list_done) { + cancel_lister_on_list_done_ = cancel_lister_on_list_done; } void OnListFile(const DirectoryLister::DirectoryListerData& data) override { + ASSERT_FALSE(done_); + file_list_.push_back(data.info); paths_.push_back(data.path); - if (quit_loop_after_each_file_) - base::MessageLoop::current()->Quit(); + if (cancel_lister_on_list_file_) { + lister_->Cancel(); + run_loop.Quit(); + } } void OnListDone(int error) override { + ASSERT_FALSE(done_); + + done_ = true; error_ = error; - base::MessageLoop::current()->Quit(); if (recursive_) CheckRecursiveSort(); else CheckSort(); + + if (cancel_lister_on_list_done_) + lister_->Cancel(); + run_loop.Quit(); } void CheckRecursiveSort() { @@ -77,25 +110,45 @@ } } + void Run(DirectoryLister* lister) { + lister_ = lister; + lister_->Start(); + run_loop.Run(); + } + int error() const { return error_; } int num_files() const { return file_list_.size(); } + bool done() const { return done_; } + private: + bool cancel_lister_on_list_file_; + bool cancel_lister_on_list_done_; + + // This is owned by the individual tests, rather than the ListerDelegate. + DirectoryLister* lister_; + + base::RunLoop run_loop; + + bool done_; int error_; bool recursive_; - bool quit_loop_after_each_file_; + std::vector<base::FileEnumerator::FileInfo> file_list_; std::vector<base::FilePath> paths_; }; +} // namespace + class DirectoryListerTest : public PlatformTest { public: - void SetUp() override { - const int kMaxDepth = 3; - const int kBranchingFactor = 4; - const int kFilesPerDirectory = 5; + DirectoryListerTest() + : total_created_file_system_objects_in_temp_root_dir_(0), + created_file_system_objects_in_temp_root_dir_(0) { + } + void SetUp() override { // Randomly create a directory structure of depth 3 in a temporary root // directory. std::list<std::pair<base::FilePath, int> > directories; @@ -110,12 +163,18 @@ base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); ASSERT_TRUE(file.IsValid()); + ++total_created_file_system_objects_in_temp_root_dir_; + if (dir_data.first == temp_root_dir_.path()) + ++created_file_system_objects_in_temp_root_dir_; } if (dir_data.second < kMaxDepth - 1) { for (int i = 0; i < kBranchingFactor; i++) { std::string dir_name = base::StringPrintf("child_dir_%d", i); base::FilePath dir_path = dir_data.first.AppendASCII(dir_name); ASSERT_TRUE(base::CreateDirectory(dir_path)); + ++total_created_file_system_objects_in_temp_root_dir_; + if (dir_data.first == temp_root_dir_.path()) + ++created_file_system_objects_in_temp_root_dir_; directories.push_back(std::make_pair(dir_path, dir_data.second + 1)); } } @@ -127,62 +186,125 @@ return temp_root_dir_.path(); } + int expected_list_length_recursive() const { + // List should include everything but the top level directory, and does not + // include "..". + return total_created_file_system_objects_in_temp_root_dir_; + } + + int expected_list_length_non_recursive() const { + // List should include everything in the top level directory, and "..". + return created_file_system_objects_in_temp_root_dir_ + 1; + } + private: + // Number of files and directories created in SetUp, excluding + // |temp_root_dir_| itself. Includes all nested directories and their files. + int total_created_file_system_objects_in_temp_root_dir_; + // Number of files and directories created directly in |temp_root_dir_|. + int created_file_system_objects_in_temp_root_dir_; + base::ScopedTempDir temp_root_dir_; }; TEST_F(DirectoryListerTest, BigDirTest) { - ListerDelegate delegate(false, false); + ListerDelegate delegate(false); DirectoryLister lister(root_path(), &delegate); - lister.Start(); + delegate.Run(&lister); - base::MessageLoop::current()->Run(); - + EXPECT_TRUE(delegate.done()); EXPECT_EQ(OK, delegate.error()); + EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files()); } TEST_F(DirectoryListerTest, BigDirRecursiveTest) { - ListerDelegate delegate(true, false); - DirectoryLister lister(root_path(), true, DirectoryLister::FULL_PATH, - &delegate); - lister.Start(); + ListerDelegate delegate(true); + DirectoryLister lister( + root_path(), true, DirectoryLister::FULL_PATH, &delegate); + delegate.Run(&lister); - base::MessageLoop::current()->Run(); - + EXPECT_TRUE(delegate.done()); EXPECT_EQ(OK, delegate.error()); -} - -TEST_F(DirectoryListerTest, CancelTest) { - ListerDelegate delegate(false, true); - DirectoryLister lister(root_path(), &delegate); - lister.Start(); - - base::MessageLoop::current()->Run(); - - int num_files = delegate.num_files(); - - lister.Cancel(); - - base::MessageLoop::current()->RunUntilIdle(); - - EXPECT_EQ(num_files, delegate.num_files()); + EXPECT_EQ(expected_list_length_recursive(), delegate.num_files()); } TEST_F(DirectoryListerTest, EmptyDirTest) { base::ScopedTempDir tempDir; EXPECT_TRUE(tempDir.CreateUniqueTempDir()); - bool kRecursive = false; - bool kQuitLoopAfterEachFile = false; - ListerDelegate delegate(kRecursive, kQuitLoopAfterEachFile); + ListerDelegate delegate(false); DirectoryLister lister(tempDir.path(), &delegate); - lister.Start(); + delegate.Run(&lister); - base::MessageLoop::current()->Run(); - - // Contains only the parent directory ("..") - EXPECT_EQ(1, delegate.num_files()); + EXPECT_TRUE(delegate.done()); EXPECT_EQ(OK, delegate.error()); + // Contains only the parent directory (".."). + EXPECT_EQ(1, delegate.num_files()); +} + +// This doesn't really test much, except make sure calling cancel before any +// callbacks are invoked doesn't crash. Can't wait for all tasks running on a +// worker pool to complete, unfortunately. +// TODO(mmenke): See if there's a way to make this fail more reliably on +// regression. +TEST_F(DirectoryListerTest, BasicCancelTest) { + ListerDelegate delegate(false); + scoped_ptr<DirectoryLister> lister(new DirectoryLister( + root_path(), &delegate)); + lister->Start(); + lister->Cancel(); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(delegate.done()); + EXPECT_EQ(0, delegate.num_files()); +} + +TEST_F(DirectoryListerTest, CancelOnListFileTest) { + ListerDelegate delegate(false); + DirectoryLister lister(root_path(), &delegate); + delegate.set_cancel_lister_on_list_file(true); + delegate.Run(&lister); + + EXPECT_FALSE(delegate.done()); + EXPECT_EQ(1, delegate.num_files()); +} + +TEST_F(DirectoryListerTest, CancelOnListDoneTest) { + ListerDelegate delegate(false); + DirectoryLister lister(root_path(), &delegate); + delegate.set_cancel_lister_on_list_done(true); + delegate.Run(&lister); + + EXPECT_TRUE(delegate.done()); + EXPECT_EQ(OK, delegate.error()); + EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files()); +} + +TEST_F(DirectoryListerTest, CancelOnLastElementTest) { + base::ScopedTempDir tempDir; + EXPECT_TRUE(tempDir.CreateUniqueTempDir()); + + ListerDelegate delegate(false); + DirectoryLister lister(tempDir.path(), &delegate); + delegate.set_cancel_lister_on_list_file(true); + delegate.Run(&lister); + + EXPECT_FALSE(delegate.done()); + // Contains only the parent directory (".."). + EXPECT_EQ(1, delegate.num_files()); +} + +TEST_F(DirectoryListerTest, NoSuchDirTest) { + base::ScopedTempDir tempDir; + EXPECT_TRUE(tempDir.CreateUniqueTempDir()); + + ListerDelegate delegate(false); + DirectoryLister lister( + tempDir.path().AppendASCII("this_path_does_not_exist"), &delegate); + delegate.Run(&lister); + + EXPECT_EQ(ERR_FILE_NOT_FOUND, delegate.error()); + EXPECT_EQ(0, delegate.num_files()); } } // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc index 3b49dff..6f28068 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc
@@ -107,6 +107,7 @@ 143, // imap2 179, // BGP 389, // ldap + 443, // https / wss (see https://crbug.com/436451) 465, // smtp+ssl 512, // print / exec 513, // login @@ -144,6 +145,11 @@ 22, // ssh }; +// HTTPS and WSS override the following restricted port. +static const int kAllowedHttpsOrWssPorts[] = { + 443, // https / wss +}; + bool IPNumberPrefixCheck(const IPAddressNumber& ip_number, const unsigned char* ip_prefix, size_t prefix_length_in_bits) { @@ -320,6 +326,29 @@ return IsPortAllowedByDefault(port); } +bool IsPortAllowedByHttpsOrWss(int port) { + int array_size = arraysize(kAllowedHttpsOrWssPorts); + for (int i = 0; i < array_size; i++) { + if (kAllowedHttpsOrWssPorts[i] == port) { + return true; + } + } + // Port not explicitly allowed by HTTPS or WSS, so return the default + // restrictions. + return IsPortAllowedByDefault(port); +} + +bool IsEffectivePortAllowedByScheme(const GURL& url) { + int port = url.EffectiveIntPort(); + if (url.SchemeIs("ftp")) { + return IsPortAllowedByFtp(port); + } else if (url.SchemeIs("https") || url.SchemeIs("wss")) { + return IsPortAllowedByHttpsOrWss(port); + } else { + return IsPortAllowedByDefault(port); + } +} + bool IsPortAllowedByOverride(int port) { if (g_explicitly_allowed_ports.Get().empty()) return false;
diff --git a/net/base/net_util.h b/net/base/net_util.h index 9e9dbad..9802097 100644 --- a/net/base/net_util.h +++ b/net/base/net_util.h
@@ -260,6 +260,15 @@ // protocol. Returns true if |port| is allowed, false if it is restricted. NET_EXPORT_PRIVATE bool IsPortAllowedByFtp(int port); +// Checks |port| against a list of ports which are restricted by the HTTPS/WSS +// protocols. Returns true if |port| is allowed, false if it is restricted. +NET_EXPORT_PRIVATE bool IsPortAllowedByHttpsOrWss(int port); + +// Checks the effective port of the |url| against a list of ports which are +// restricted by the scheme of the |url|. Returns true if the port is allowed, +// false if it is restricted. +NET_EXPORT_PRIVATE bool IsEffectivePortAllowedByScheme(const GURL& url); + // Check if banned |port| has been overriden by an entry in // |explicitly_allowed_ports_|. NET_EXPORT_PRIVATE bool IsPortAllowedByOverride(int port);
diff --git a/net/disk_cache/blockfile/sparse_control.cc b/net/disk_cache/blockfile/sparse_control.cc index 30ea836..e5096dc 100644 --- a/net/disk_cache/blockfile/sparse_control.cc +++ b/net/disk_cache/blockfile/sparse_control.cc
@@ -483,7 +483,7 @@ return KillChildAndContinue(key, false); if (child_data_.header.last_block_len < 0 || - child_data_.header.last_block_len > kBlockSize) { + child_data_.header.last_block_len >= kBlockSize) { // Make sure these values are always within range. child_data_.header.last_block_len = 0; child_data_.header.last_block = -1; @@ -590,7 +590,7 @@ if (child_map_.FindNextBit(&start, last_bit, false)) { // Something is not here. DCHECK_GE(child_data_.header.last_block_len, 0); - DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize); + DCHECK_LT(child_data_.header.last_block_len, kBlockSize); int partial_block_len = PartialBlockLength(start); if (start == child_offset_ >> 10) { // It looks like we don't have anything. @@ -615,7 +615,7 @@ return; DCHECK_GE(child_data_.header.last_block_len, 0); - DCHECK_LT(child_data_.header.last_block_len, kMaxEntrySize); + DCHECK_LT(child_data_.header.last_block_len, kBlockSize); // Write the bitmap. int first_bit = child_offset_ >> 10; @@ -651,11 +651,6 @@ if (block_index == child_data_.header.last_block) return child_data_.header.last_block_len; - // This may be the last stored index. - int entry_len = child_->GetDataSize(kSparseData); - if (block_index == entry_len >> 10) - return entry_len & (kBlockSize - 1); - // This is really empty. return 0; } @@ -769,27 +764,49 @@ if (!child_) return child_len_; // Move on to the next child. - // Check that there are no holes in this range. - int last_bit = (child_offset_ + child_len_ + 1023) >> 10; + // Bits on the bitmap should only be set when the corresponding block was + // fully written (it's really being used). If a block is partially used, it + // has to start with valid data, the length of the valid data is saved in + // |header.last_block_len| and the block itself should match + // |header.last_block|. + // + // In other words, (|header.last_block| + |header.last_block_len|) is the + // offset where the last write ended, and data in that block (which is not + // marked as used because it is not full) will only be reused if the next + // write continues at that point. + // + // This code has to find if there is any data between child_offset_ and + // child_offset_ + child_len_. + int last_bit = (child_offset_ + child_len_ + kBlockSize - 1) >> 10; int start = child_offset_ >> 10; int partial_start_bytes = PartialBlockLength(start); int found = start; int bits_found = child_map_.FindBits(&found, last_bit, true); + bool is_last_block_in_range = start < child_data_.header.last_block && + child_data_.header.last_block < last_bit; - // We don't care if there is a partial block in the middle of the range. int block_offset = child_offset_ & (kBlockSize - 1); - if (!bits_found && partial_start_bytes <= block_offset) - return child_len_; + if (!bits_found && partial_start_bytes <= block_offset) { + if (!is_last_block_in_range) + return child_len_; + found = last_bit - 1; // There are some bytes here. + } // We are done. Just break the loop and reset result_ to our real result. range_found_ = true; - // found now points to the first 1. Lets see if we have zeros before it. - int empty_start = std::max((found << 10) - child_offset_, 0); - int bytes_found = bits_found << 10; bytes_found += PartialBlockLength(found + bits_found); + // found now points to the first bytes. Lets see if we have data before it. + int empty_start = std::max((found << 10) - child_offset_, 0); + if (empty_start >= child_len_) + return child_len_; + + // At this point we have bytes_found stored after (found << 10), and we want + // child_len_ bytes after child_offset_. The first empty_start bytes after + // child_offset_ are invalid. + if (start == found) bytes_found -= block_offset; @@ -798,7 +815,7 @@ // query that we have to subtract from the range that we searched. result_ = std::min(bytes_found, child_len_ - empty_start); - if (!bits_found) { + if (partial_start_bytes) { result_ = std::min(partial_start_bytes - block_offset, child_len_); empty_start = 0; }
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc index aac45ac..03cc86b 100644 --- a/net/disk_cache/entry_unittest.cc +++ b/net/disk_cache/entry_unittest.cc
@@ -1798,6 +1798,111 @@ GetAvailableRange(); } +// Tests that non-sequential writes that are not aligned with the minimum sparse +// data granularity (1024 bytes) do in fact result in dropped data. +TEST_F(DiskCacheEntryTest, SparseWriteDropped) { + InitCache(); + std::string key("the first key"); + disk_cache::Entry* entry; + ASSERT_EQ(net::OK, CreateEntry(key, &entry)); + + const int kSize = 180; + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); + CacheTestFillBuffer(buf_1->data(), kSize, false); + + // Do small writes (180 bytes) that get increasingly close to a 1024-byte + // boundary. All data should be dropped until a boundary is crossed, at which + // point the data after the boundary is saved (at least for a while). + int offset = 1024 - 500; + int rv = 0; + net::TestCompletionCallback cb; + int64 start; + for (int i = 0; i < 5; i++) { + // Check result of last GetAvailableRange. + EXPECT_EQ(0, rv); + + rv = entry->WriteSparseData(offset, buf_1.get(), kSize, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + + rv = entry->GetAvailableRange(offset - 100, kSize, &start, cb.callback()); + EXPECT_EQ(0, cb.GetResult(rv)); + + rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback()); + rv = cb.GetResult(rv); + if (!rv) { + rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback()); + EXPECT_EQ(0, cb.GetResult(rv)); + rv = 0; + } + offset += 1024 * i + 100; + } + + // The last write started 100 bytes below a bundary, so there should be 80 + // bytes after the boundary. + EXPECT_EQ(80, rv); + EXPECT_EQ(1024 * 7, start); + rv = entry->ReadSparseData(start, buf_2.get(), kSize, cb.callback()); + EXPECT_EQ(80, cb.GetResult(rv)); + EXPECT_EQ(0, memcmp(buf_1.get()->data() + 100, buf_2.get()->data(), 80)); + + // And even that part is dropped when another write changes the offset. + offset = start; + rv = entry->WriteSparseData(0, buf_1.get(), kSize, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + + rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback()); + EXPECT_EQ(0, cb.GetResult(rv)); + entry->Close(); +} + +// Tests that small sequential writes are not dropped. +TEST_F(DiskCacheEntryTest, SparseSquentialWriteNotDropped) { + InitCache(); + std::string key("the first key"); + disk_cache::Entry* entry; + ASSERT_EQ(net::OK, CreateEntry(key, &entry)); + + const int kSize = 180; + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); + CacheTestFillBuffer(buf_1->data(), kSize, false); + + // Any starting offset is fine as long as it is 1024-bytes aligned. + int rv = 0; + net::TestCompletionCallback cb; + int64 start; + int64 offset = 1024 * 11; + for (; offset < 20000; offset += kSize) { + rv = entry->WriteSparseData(offset, buf_1.get(), kSize, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + + rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + EXPECT_EQ(offset, start); + + rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + EXPECT_EQ(0, memcmp(buf_1.get()->data(), buf_2.get()->data(), kSize)); + } + + entry->Close(); + FlushQueueForTest(); + + // Verify again the last write made. + ASSERT_EQ(net::OK, OpenEntry(key, &entry)); + offset -= kSize; + rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + EXPECT_EQ(offset, start); + + rv = entry->ReadSparseData(offset, buf_2.get(), kSize, cb.callback()); + EXPECT_EQ(kSize, cb.GetResult(rv)); + EXPECT_EQ(0, memcmp(buf_1.get()->data(), buf_2.get()->data(), kSize)); + + entry->Close(); +} + void DiskCacheEntryTest::CouldBeSparse() { std::string key("the first key"); disk_cache::Entry* entry; @@ -2133,7 +2238,11 @@ EXPECT_EQ(0, ReadSparseData(entry, 0, buf2.get(), kSize)); // This read should not change anything. - EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2.get(), kSize)); + if (memory_only_ || simple_cache_mode_) + EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2.get(), kSize)); + else + EXPECT_EQ(0, ReadSparseData(entry, 24000, buf2.get(), kSize)); + EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2.get(), kSize)); EXPECT_EQ(0, ReadSparseData(entry, 99, buf2.get(), kSize)); @@ -2153,7 +2262,11 @@ EXPECT_EQ(500, cb.GetResult(rv)); EXPECT_EQ(kSize, start); rv = entry->GetAvailableRange(20 * 1024, 10000, &start, cb.callback()); - EXPECT_EQ(3616, cb.GetResult(rv)); + if (memory_only_ || simple_cache_mode_) + EXPECT_EQ(3616, cb.GetResult(rv)); + else + EXPECT_EQ(3072, cb.GetResult(rv)); + EXPECT_EQ(20 * 1024, start); // 1. Query before a filled 1KB block.
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 74bd6bf..17d5754 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc
@@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/compiler_specific.h" #include "base/metrics/histogram.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/string_split.h" @@ -372,6 +373,11 @@ } void FtpNetworkTransaction::OnIOComplete(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 FtpNetworkTransaction::OnIOComplete")); + int rv = DoLoop(result); if (rv != ERR_IO_PENDING) DoCallback(rv);
diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc index fd3a6fa..6a5ee17 100644 --- a/net/http/disk_cache_based_quic_server_info.cc +++ b/net/http/disk_cache_based_quic_server_info.cc
@@ -200,12 +200,18 @@ rv = DoLoop(rv); if (rv == ERR_IO_PENDING) return; + + base::WeakPtr<DiskCacheBasedQuicServerInfo> weak_this = + weak_factory_.GetWeakPtr(); + if (!wait_for_ready_callback_.is_null()) { wait_for_data_end_time_ = base::TimeTicks::Now(); RecordLastFailure(); base::ResetAndReturn(&wait_for_ready_callback_).Run(rv); } - if (ready_ && !pending_write_data_.empty()) { + // |wait_for_ready_callback_| could delete the object if there is an error. + // Check if |weak_this| still exists before accessing it. + if (weak_this.get() && ready_ && !pending_write_data_.empty()) { DCHECK_EQ(NONE, state_); PersistInternal(); }
diff --git a/net/http/disk_cache_based_quic_server_info_unittest.cc b/net/http/disk_cache_based_quic_server_info_unittest.cc index 847b3d8..ef69b43 100644 --- a/net/http/disk_cache_based_quic_server_info_unittest.cc +++ b/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -14,6 +14,8 @@ #include "net/quic/quic_server_id.h" #include "testing/gtest/include/gtest/gtest.h" +using std::string; + namespace net { namespace { @@ -48,6 +50,27 @@ 0 }; +class DeleteCacheCompletionCallback : public net::TestCompletionCallbackBase { + public: + explicit DeleteCacheCompletionCallback(QuicServerInfo* server_info) + : server_info_(server_info), + callback_(base::Bind(&DeleteCacheCompletionCallback::OnComplete, + base::Unretained(this))) {} + + const net::CompletionCallback& callback() const { return callback_; } + + private: + void OnComplete(int result) { + delete server_info_; + SetResult(result); + } + + QuicServerInfo* server_info_; + net::CompletionCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(DeleteCacheCompletionCallback); +}; + } // namespace // Tests that we can delete a DiskCacheBasedQuicServerInfo object in a @@ -582,4 +605,24 @@ RemoveMockTransaction(&kHostInfoTransaction1); } +// crbug.com/439209: test deletion of QuicServerInfo object in the callback +// doesn't crash. +TEST(DiskCacheBasedQuicServerInfo, DeleteServerInfoInCallback) { + // Use the blocking mock backend factory to force asynchronous completion + // of quic_server_info->WaitForDataReady(), so that the callback will run. + MockBlockingBackendFactory* factory = new MockBlockingBackendFactory(); + MockHttpCache cache(factory); + QuicServerId server_id("www.verisign.com", 443, true, PRIVACY_MODE_DISABLED); + QuicServerInfo* quic_server_info = + new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()); + // |cb| takes owndership and deletes |quic_server_info| when it is called. + DeleteCacheCompletionCallback cb(quic_server_info); + quic_server_info->Start(); + int rv = quic_server_info->WaitForDataReady(cb.callback()); + EXPECT_EQ(ERR_IO_PENDING, rv); + // Now complete the backend creation and let the callback run. + factory->FinishCreation(); + EXPECT_EQ(OK, cb.GetResult(rv)); +} + } // namespace net
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc index 422ddd7..557051c 100644 --- a/net/http/http_auth_handler_negotiate.cc +++ b/net/http/http_auth_handler_negotiate.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/logging.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/stringprintf.h" #include "net/base/address_family.h" #include "net/base/net_errors.h" @@ -232,6 +233,11 @@ } void HttpAuthHandlerNegotiate::OnIOComplete(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 HttpAuthHandlerNegotiate::OnIOComplete")); + int rv = DoLoop(result); if (rv != ERR_IO_PENDING) DoCallback(rv);
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index a167e32..a34bef1 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -603,7 +603,7 @@ void HttpCache::OnExternalCacheHit(const GURL& url, const std::string& http_method) { - if (!disk_cache_.get()) + if (!disk_cache_.get() || mode_ == DISABLE) return; HttpRequestInfo request_info;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index eacd06c..a0248fe 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -3262,8 +3262,8 @@ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); // fetch https://www.google.com/ via HTTP const char get[] = "GET / HTTP/1.1\r\n" @@ -3349,8 +3349,8 @@ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); // fetch https://www.google.com/ via SPDY const char* const kMyUrl = "https://www.google.com/"; scoped_ptr<SpdyFrame> get( @@ -3438,8 +3438,8 @@ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> get( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); @@ -3501,8 +3501,8 @@ request2.load_flags = 0; // CONNECT to www.google.com:443 via SPDY. - scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> conn_resp1( spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); @@ -3651,8 +3651,8 @@ request2.load_flags = 0; // CONNECT to www.google.com:443 via SPDY. - scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> conn_resp1( spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); @@ -6220,8 +6220,8 @@ request.url = GURL("https://www.google.com/"); request.load_flags = 0; - scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> goaway( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite data_writes[] = { @@ -6329,8 +6329,8 @@ request.url = GURL("https://www.google.com/"); request.load_flags = 0; - scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite data_writes[] = { @@ -6396,8 +6396,8 @@ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); // Since we have proxy, should try to establish tunnel. - scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); @@ -6407,7 +6407,8 @@ "proxy-authorization", "Basic Zm9vOmJhcg==", }; scoped_ptr<SpdyFrame> connect2(spdy_util_.ConstructSpdyConnect( - kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST)); + kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST, + HostPortPair("www.google.com", 443))); // fetch https://www.google.com/ via HTTP const char get[] = "GET / HTTP/1.1\r\n" "Host: www.google.com\r\n" @@ -11312,8 +11313,8 @@ #undef MAYBE_UseIPConnectionPoolingWithHostCacheExpiration TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) { - const std::string https_url = "https://www.google.com/"; - const std::string http_url = "http://www.google.com:443/"; + const std::string https_url = "https://www.google.com:8080/"; + const std::string http_url = "http://www.google.com:8080/"; // SPDY GET for HTTPS URL scoped_ptr<SpdyFrame> req1( @@ -11339,10 +11340,10 @@ // HTTP GET for the HTTP URL MockWrite writes2[] = { - MockWrite(ASYNC, 4, - "GET / HTTP/1.1\r\n" - "Host: www.google.com:443\r\n" - "Connection: keep-alive\r\n\r\n"), + MockWrite(ASYNC, 4, + "GET / HTTP/1.1\r\n" + "Host: www.google.com:8080\r\n" + "Connection: keep-alive\r\n\r\n"), }; MockRead reads2[] = { @@ -11393,12 +11394,13 @@ } TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) { - const std::string https_url = "https://www.google.com/"; - const std::string http_url = "http://www.google.com:443/"; + const std::string https_url = "https://www.google.com:8080/"; + const std::string http_url = "http://www.google.com:8080/"; // SPDY GET for HTTPS URL (through CONNECT tunnel) - scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1, - LOWEST)); + const HostPortPair host_port_pair("www.google.com", 8080); + scoped_ptr<SpdyFrame> connect( + spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOWEST, host_port_pair)); scoped_ptr<SpdyFrame> req1( spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST)); scoped_ptr<SpdyFrame> wrapped_req1( @@ -11408,7 +11410,7 @@ SpdyHeaderBlock req2_block; req2_block[spdy_util_.GetMethodKey()] = "GET"; req2_block[spdy_util_.GetPathKey()] = "/"; - req2_block[spdy_util_.GetHostKey()] = "www.google.com:443"; + req2_block[spdy_util_.GetHostKey()] = "www.google.com:8080"; req2_block[spdy_util_.GetSchemeKey()] = "http"; spdy_util_.MaybeAddVersionHeader(&req2_block); scoped_ptr<SpdyFrame> req2( @@ -11505,8 +11507,8 @@ TEST_P(HttpNetworkTransactionTest, UseSpdySessionForHttpWhenForced) { session_deps_.force_spdy_always = true; - const std::string https_url = "https://www.google.com/"; - const std::string http_url = "http://www.google.com:443/"; + const std::string https_url = "https://www.google.com:8080/"; + const std::string http_url = "http://www.google.com:8080/"; // SPDY GET for HTTPS URL scoped_ptr<SpdyFrame> req1(
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index f818432..909da62 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -393,8 +393,8 @@ MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"), MockRead(ASYNC, 4, "0123456789"), }; - scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOW)); + scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( + NULL, 0, 1, LOW, HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite spdy_writes[] = { @@ -502,7 +502,8 @@ }; scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW)); + spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW, + HostPortPair("www.google.com", 443))); MockWrite spdy_writes[] = { CreateMockWrite(*req, 0, ASYNC) }; @@ -544,8 +545,8 @@ return; scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, - 1, MEDIUM)); + spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM, + HostPortPair("www.google.com", 443))); MockWrite spdy_writes[] = { CreateMockWrite(*req, 0, ASYNC) }; @@ -651,7 +652,8 @@ MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2), }; scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW)); + spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW, + HostPortPair("www.google.com", 443))); MockWrite spdy_writes[] = { CreateMockWrite(*req, 0, ASYNC) }; @@ -725,7 +727,8 @@ MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"), }; scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW)); + spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW, + HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); MockWrite spdy_writes[] = { @@ -776,7 +779,8 @@ MockRead(ASYNC, 1, responseText.c_str()), }; scoped_ptr<SpdyFrame> req( - spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW)); + spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW, + HostPortPair("www.google.com", 443))); scoped_ptr<SpdyFrame> rst( spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 8369443..5887d2a 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -623,15 +623,15 @@ &request_info_.url, &origin_url_, priority_)); - // Don't connect to restricted ports. - bool is_port_allowed = IsPortAllowedByDefault(origin_.port()); if (request_info_.url.SchemeIs("ftp")) { // Never share connection with other jobs for FTP requests. DCHECK(!waiting_job_); - - is_port_allowed = IsPortAllowedByFtp(origin_.port()); } - if (!is_port_allowed && !IsPortAllowedByOverride(origin_.port())) { + + // Don't connect to restricted ports. + // Note: origin_.port() == request_info_.url.EffectiveIntPort() + if (!IsEffectivePortAllowedByScheme(request_info_.url) && + !IsPortAllowedByOverride(origin_.port())) { if (waiting_job_) { waiting_job_->Resume(this); waiting_job_ = NULL;
diff --git a/net/proxy/proxy_script_decider.cc b/net/proxy/proxy_script_decider.cc index 939f7af..47e6ca8 100644 --- a/net/proxy/proxy_script_decider.cc +++ b/net/proxy/proxy_script_decider.cc
@@ -10,6 +10,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" @@ -164,6 +165,11 @@ } void ProxyScriptDecider::OnIOCompletion(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 ProxyScriptDecider::OnIOCompletion")); + DCHECK_NE(STATE_NONE, next_state_); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) {
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc index 7653943..eedebe5 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.cc +++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -14,6 +14,7 @@ using std::make_pair; using std::max; using std::min; +using std::string; using std::vector; namespace net {
diff --git a/net/quic/congestion_control/send_algorithm_simulator.h b/net/quic/congestion_control/send_algorithm_simulator.h index 7f52d8f..2685d23 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.h +++ b/net/quic/congestion_control/send_algorithm_simulator.h
@@ -80,7 +80,7 @@ Transfer(Sender* sender, QuicByteCount num_bytes, QuicTime start_time, - string name); + std::string name); Sender* sender; QuicByteCount num_bytes; @@ -88,7 +88,7 @@ QuicByteCount bytes_lost; QuicByteCount bytes_in_flight; QuicTime start_time; - string name; + std::string name; }; struct SentPacket { @@ -157,8 +157,10 @@ void AddTransfer(Sender* sender, size_t num_bytes); // Adds a pending sending to start at the specified time. - void AddTransfer( - Sender* sender, size_t num_bytes, QuicTime start_time, string name); + void AddTransfer(Sender* sender, + size_t num_bytes, + QuicTime start_time, + std::string name); // Convenience method to transfer all bytes. void TransferBytes();
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc index 37ee8f9..037bf7e 100644 --- a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -7,6 +7,7 @@ #include "net/quic/test_tools/quic_test_utils.h" using base::StringPiece; +using std::string; namespace {
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc index 8ccaaed..b7345b5 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -7,6 +7,7 @@ #include "net/quic/test_tools/quic_test_utils.h" using base::StringPiece; +using std::string; namespace {
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc index e83acc0..312e2d4 100644 --- a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc +++ b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
@@ -7,6 +7,7 @@ #include "net/quic/test_tools/quic_test_utils.h" using base::StringPiece; +using std::string; namespace {
diff --git a/net/quic/crypto/chacha20_poly1305_encrypter_test.cc b/net/quic/crypto/chacha20_poly1305_encrypter_test.cc index 4f33337..5b05c7f 100644 --- a/net/quic/crypto/chacha20_poly1305_encrypter_test.cc +++ b/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
@@ -7,6 +7,7 @@ #include "net/quic/test_tools/quic_test_utils.h" using base::StringPiece; +using std::string; namespace {
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc index 23e8ea2..6ed8014 100644 --- a/net/quic/crypto/crypto_handshake_message.cc +++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -244,7 +244,6 @@ case kCFCW: case kSFCW: case kIRTT: - case kKATO: case kMSPC: case kSWND: // uint32 value
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 57a5508..a9337a5 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -94,7 +94,7 @@ const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state // lifetime -const QuicTag kKATO = TAG('K', 'A', 'T', 'O'); // Keepalive timeout +const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout const QuicTag kMSPC = TAG('M', 'S', 'P', 'C'); // Max streams per connection. const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us. const QuicTag kSWND = TAG('S', 'W', 'N', 'D'); // Server's Initial congestion
diff --git a/net/quic/crypto/crypto_utils_test.cc b/net/quic/crypto/crypto_utils_test.cc index 882a9b5..1395cc3 100644 --- a/net/quic/crypto/crypto_utils_test.cc +++ b/net/quic/crypto/crypto_utils_test.cc
@@ -7,6 +7,8 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +using std::string; + namespace net { namespace test { namespace {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index ef8bc20..1a99cf9 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc
@@ -761,6 +761,7 @@ read_buffer_->size(), base::Bind(&QuicClientSession::OnReadComplete, weak_factory_.GetWeakPtr())); + UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING); if (rv == ERR_IO_PENDING) { num_packets_read_ = 0; return;
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index d2a10a4..bb686e7 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc
@@ -431,7 +431,7 @@ congestion_feedback_(kCGST, PRESENCE_REQUIRED), connection_options_(kCOPT, PRESENCE_OPTIONAL), idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED), - keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL), + silent_close_(kSCLS, PRESENCE_OPTIONAL), max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), @@ -493,9 +493,12 @@ idle_connection_state_lifetime_seconds_.GetUint32()); } -QuicTime::Delta QuicConfig::KeepaliveTimeout() const { - return QuicTime::Delta::FromSeconds( - keepalive_timeout_seconds_.GetUint32()); +void QuicConfig::SetSilentClose(bool silent_close) { + silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0); +} + +bool QuicConfig::SilentClose() const { + return silent_close_.GetUint32() > 0; } void QuicConfig::SetMaxStreamsPerConnection(size_t max_streams, @@ -631,7 +634,6 @@ // ProcessServerHello. return congestion_feedback_.negotiated() && idle_connection_state_lifetime_seconds_.negotiated() && - keepalive_timeout_seconds_.negotiated() && max_streams_per_connection_.negotiated(); } @@ -641,8 +643,11 @@ congestion_feedback_.set(congestion_feedback, kQBIC); idle_connection_state_lifetime_seconds_.set(kMaximumIdleTimeoutSecs, kDefaultIdleTimeoutSecs); - // kKATO is optional. Return 0 if not negotiated. - keepalive_timeout_seconds_.set(0, 0); + if (FLAGS_quic_allow_silent_close) { + silent_close_.set(1, 0); + } else { + silent_close_.set(0, 0); + } SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection); max_time_before_crypto_handshake_ = @@ -659,7 +664,7 @@ void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { congestion_feedback_.ToHandshakeMessage(out); idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out); - keepalive_timeout_seconds_.ToHandshakeMessage(out); + silent_close_.ToHandshakeMessage(out); max_streams_per_connection_.ToHandshakeMessage(out); bytes_for_connection_id_.ToHandshakeMessage(out); initial_round_trip_time_us_.ToHandshakeMessage(out); @@ -686,8 +691,8 @@ peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { - error = keepalive_timeout_seconds_.ProcessPeerHello( - peer_hello, hello_type, error_details); + error = + silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { error = max_streams_per_connection_.ProcessPeerHello(
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 507dd9d..12097f8 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h
@@ -277,7 +277,9 @@ QuicTime::Delta IdleConnectionStateLifetime() const; - QuicTime::Delta KeepaliveTimeout() const; + void SetSilentClose(bool silent_close); + + bool SilentClose() const; void SetMaxStreamsPerConnection(size_t max_streams, size_t default_streams); @@ -400,8 +402,8 @@ QuicFixedTagVector connection_options_; // Idle connection state lifetime QuicNegotiableUint32 idle_connection_state_lifetime_seconds_; - // Keepalive timeout, or 0 to turn off keepalive probes - QuicNegotiableUint32 keepalive_timeout_seconds_; + // Whether to use silent close. Defaults to 0 (false) and is otherwise true. + QuicNegotiableUint32 silent_close_; // Maximum number of streams that the connection can support. QuicNegotiableUint32 max_streams_per_connection_; // The number of bytes required for the connection ID.
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index 413d7fb..36321d1 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc
@@ -95,6 +95,7 @@ client_config.SetConnectionOptionsToSend(copt); CryptoHandshakeMessage msg; client_config.ToHandshakeMessage(&msg); + string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); @@ -105,7 +106,6 @@ config_.IdleConnectionStateLifetime()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, config_.MaxStreamsPerConnection()); - EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout()); EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); EXPECT_TRUE(config_.HasReceivedConnectionOptions()); EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); @@ -152,7 +152,6 @@ config_.IdleConnectionStateLifetime()); EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2, config_.MaxStreamsPerConnection()); - EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout()); EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(), 2 * kInitialSessionFlowControlWindowForTest); @@ -179,6 +178,7 @@ const QuicErrorCode error = config_.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_TRUE(config_.negotiated()); EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes()); } @@ -196,6 +196,7 @@ const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); + EXPECT_TRUE(config_.negotiated()); EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes()); }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index c33aec5..74d1758 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -192,7 +192,8 @@ bool is_server, bool is_secure, const QuicVersionVector& supported_versions) - : framer_(supported_versions, helper->GetClock()->ApproximateNow(), + : framer_(supported_versions, + helper->GetClock()->ApproximateNow(), is_server), helper_(helper), writer_(writer_factory.Create(this)), @@ -213,6 +214,7 @@ largest_seen_packet_with_stop_waiting_(0), max_undecryptable_packets_(0), pending_version_negotiation_packet_(false), + silent_close_enabled_(false), received_packet_manager_(&stats_), ack_queued_(false), num_packets_received_since_last_ack_sent_(0), @@ -230,7 +232,9 @@ time_of_last_sent_new_packet_(clock_->ApproximateNow()), sequence_number_of_last_sent_packet_(0), sent_packet_manager_( - is_server, clock_, &stats_, + is_server, + clock_, + &stats_, FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic, FLAGS_quic_use_time_loss_detection ? kTime : kNack, is_secure), @@ -268,6 +272,9 @@ if (config.negotiated()) { SetNetworkTimeouts(QuicTime::Delta::Infinite(), config.IdleConnectionStateLifetime()); + if (FLAGS_quic_allow_silent_close && config.SilentClose()) { + silent_close_enabled_ = true; + } } else { SetNetworkTimeouts(config.max_time_before_crypto_handshake(), config.max_idle_time_before_crypto_handshake()); @@ -313,14 +320,8 @@ void QuicConnection::OnError(QuicFramer* framer) { // Packets that we can not or have not decrypted are dropped. // TODO(rch): add stats to measure this. - if (FLAGS_quic_drop_junk_packets) { - if (!connected_ || last_packet_decrypted_ == false) { - return; - } - } else { - if (!connected_ || framer->error() == QUIC_DECRYPTION_FAILURE) { - return; - } + if (!connected_ || last_packet_decrypted_ == false) { + return; } SendConnectionCloseWithDetails(framer->error(), framer->detailed_error()); } @@ -1854,6 +1855,12 @@ DVLOG(1) << ENDPOINT << "Force closing " << connection_id() << " with error " << QuicUtils::ErrorToString(error) << " (" << error << ") " << details; + // Don't send explicit connection close packets for timeouts. + // This is particularly important on mobile, where connections are short. + if (silent_close_enabled_ && + error == QuicErrorCode::QUIC_CONNECTION_TIMED_OUT) { + return; + } ScopedPacketBundler ack_bundler(this, SEND_ACK); QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(); frame->error_code = error;
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 14c45a1..76dabff 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h
@@ -745,6 +745,9 @@ // Contains the connection close packet if the connection has been closed. scoped_ptr<QuicEncryptedPacket> connection_close_packet_; + // When true, the connection does not send a close packet on timeout. + bool silent_close_enabled_; + FecGroupMap group_map_; QuicReceivedPacketManager received_packet_manager_;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 32d7544..cb46bd9 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -31,6 +31,7 @@ using base::StringPiece; using std::map; +using std::string; using std::vector; using testing::AnyNumber; using testing::AtLeast; @@ -2987,6 +2988,7 @@ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)); QuicConfig config; connection_.SetFromConfig(config); + EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); const QuicTime::Delta initial_idle_timeout = QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); @@ -3021,6 +3023,67 @@ EXPECT_FALSE(connection_.connected()); } +TEST_P(QuicConnectionTest, TimeoutAfterSendSilentClose) { + // Same test as above, but complete a handshake which enables silent close, + // causing no connection close packet to be sent. + ValueRestore<bool> old_flag(&FLAGS_quic_allow_silent_close, true); + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)); + QuicConfig config; + + // Create a handshake message that also enables silent close. + CryptoHandshakeMessage msg; + string error_details; + QuicConfig client_config; + client_config.SetInitialFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + client_config.SetInitialStreamFlowControlWindowToSend( + kInitialStreamFlowControlWindowForTest); + client_config.SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + client_config.SetIdleConnectionStateLifetime( + QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), + QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); + client_config.ToHandshakeMessage(&msg); + const QuicErrorCode error = + config.ProcessPeerHello(msg, CLIENT, &error_details); + EXPECT_EQ(QUIC_NO_ERROR, error); + + connection_.SetFromConfig(config); + EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); + + const QuicTime::Delta default_idle_timeout = + QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1); + const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); + QuicTime default_timeout = clock_.ApproximateNow().Add(default_idle_timeout); + + // When we send a packet, the timeout will change to 5ms + + // kInitialIdleTimeoutSecs. + clock_.AdvanceTime(five_ms); + + // Send an ack so we don't set the retransmission alarm. + SendAckPacketToPeer(); + EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline()); + + // The original alarm will fire. We should not time out because we had a + // network event at t=5ms. The alarm will reregister. + clock_.AdvanceTime(default_idle_timeout.Subtract(five_ms)); + EXPECT_EQ(default_timeout, clock_.ApproximateNow()); + connection_.GetTimeoutAlarm()->Fire(); + EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); + EXPECT_TRUE(connection_.connected()); + EXPECT_EQ(default_timeout.Add(five_ms), + connection_.GetTimeoutAlarm()->deadline()); + + // This time, we should time out. + EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false)); + clock_.AdvanceTime(five_ms); + EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow()); + connection_.GetTimeoutAlarm()->Fire(); + EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); + EXPECT_FALSE(connection_.connected()); +} + TEST_P(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index fd740dd..6777b2e 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc
@@ -12,6 +12,8 @@ #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" +using std::string; + namespace net { QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index f2a4244..ae9304c 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h
@@ -81,7 +81,7 @@ // ProofVerifierCallback interface. void Run(bool ok, - const string& error_details, + const std::string& error_details, scoped_ptr<ProofVerifyDetails>* details) override; // Cancel causes any future callbacks to be ignored. It must be called on @@ -208,7 +208,7 @@ // verification. These members must not be used after // STATE_VERIFY_PROOF_COMPLETE. bool verify_ok_; - string verify_error_details_; + std::string verify_error_details_; scoped_ptr<ProofVerifyDetails> verify_details_; DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 8e14d77..584b6fb 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -18,6 +18,8 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using std::string; + namespace net { namespace test { namespace { @@ -98,7 +100,6 @@ config->IdleConnectionStateLifetime().ToSeconds()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, config->MaxStreamsPerConnection()); - EXPECT_EQ(0, config->KeepaliveTimeout().ToSeconds()); const QuicCryptoNegotiatedParameters& crypto_params( stream_->crypto_negotiated_params());
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index c4b5893..baf8a93 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc
@@ -15,6 +15,8 @@ #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" +using std::string; + namespace net { void ServerHelloNotifier::OnAckNotification(
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index f3ea48a..ebb5af2 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -32,6 +32,7 @@ } // namespace net using std::pair; +using std::string; using testing::_; namespace net {
diff --git a/net/quic/quic_data_stream.h b/net/quic/quic_data_stream.h index 0337b30..965a5ae 100644 --- a/net/quic/quic_data_stream.h +++ b/net/quic/quic_data_stream.h
@@ -12,6 +12,7 @@ #include <sys/types.h> #include <list> +#include <string> #include "base/basictypes.h" #include "base/strings/string_piece.h" @@ -133,7 +134,7 @@ QuicPriority priority_; // Contains a copy of the decompressed headers until they are consumed // via ProcessData or Readv. - string decompressed_headers_; + std::string decompressed_headers_; // True if an error was encountered during decompression. bool decompression_failed_; // True if the priority has been read, false otherwise.
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc index 16e6341..cc865c0 100644 --- a/net/quic/quic_data_stream_test.cc +++ b/net/quic/quic_data_stream_test.cc
@@ -18,6 +18,7 @@ using base::StringPiece; using std::min; +using std::string; using testing::AnyNumber; using testing::InSequence; using testing::Return;
diff --git a/net/quic/quic_default_packet_writer.cc b/net/quic/quic_default_packet_writer.cc index d851dfb..177d292 100644 --- a/net/quic/quic_default_packet_writer.cc +++ b/net/quic/quic_default_packet_writer.cc
@@ -6,6 +6,7 @@ #include "base/location.h" #include "base/logging.h" +#include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -24,12 +25,14 @@ QuicDefaultPacketWriter::~QuicDefaultPacketWriter() {} WriteResult QuicDefaultPacketWriter::WritePacket( - const char* buffer, size_t buf_len, + const char* buffer, + size_t buf_len, const net::IPAddressNumber& self_address, const net::IPEndPoint& peer_address) { scoped_refptr<StringIOBuffer> buf( new StringIOBuffer(std::string(buffer, buf_len))); DCHECK(!IsWriteBlocked()); + base::TimeTicks now = base::TimeTicks::Now(); int rv = socket_->Write(buf.get(), buf_len, base::Bind(&QuicDefaultPacketWriter::OnWriteComplete, @@ -45,6 +48,13 @@ } } + base::TimeDelta delta = base::TimeTicks::Now() - now; + if (status == WRITE_STATUS_OK) { + UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Synchronous", delta); + } else if (status == WRITE_STATUS_BLOCKED) { + UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Asynchronous", delta); + } + return WriteResult(status, rv); }
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index c9658c1..306ac2d 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -32,10 +32,6 @@ // When true, defaults to BBR congestion control instead of Cubic. bool FLAGS_quic_use_bbr_congestion_control = false; -// If true, QUIC will be more resilliant to junk packets with valid connection -// IDs. -bool FLAGS_quic_drop_junk_packets = true; - // If true, QUIC BBR congestion control may be enabled via Finch and/or via QUIC // connection options. bool FLAGS_quic_allow_bbr = false; @@ -61,3 +57,11 @@ // If true, enables the QUIC bandwidth resumption experiment (triggered by // Chrome/Finch). bool FLAGS_quic_enable_bandwidth_resumption_experiment = true; + +// If true, QUIC congestion control will be paced. If false, pacing may be +// controlled by QUIC connection options in the config or by enabling BBR +// congestion control. +bool FLAGS_quic_enable_pacing = false; + +// If true, the silent close option will be honored. +bool FLAGS_quic_allow_silent_close = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index 32c5edf..05e939e 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -14,7 +14,6 @@ NET_EXPORT_PRIVATE extern bool FLAGS_send_quic_crypto_reject_reason; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_fec; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_bbr_congestion_control; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_junk_packets; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr; NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic; NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets; @@ -22,5 +21,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write; NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_bandwidth_resumption_experiment; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_pacing; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_silent_close; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc index 10a02a7..9d26e4a 100644 --- a/net/quic/quic_headers_stream.cc +++ b/net/quic/quic_headers_stream.cc
@@ -7,6 +7,7 @@ #include "net/quic/quic_session.h" using base::StringPiece; +using std::string; namespace net {
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc index caa697a..4da460c 100644 --- a/net/quic/quic_reliable_client_stream_test.cc +++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -90,7 +90,7 @@ TEST_P(QuicReliableClientStreamTest, OnFinRead) { InitializeHeaders(); - string uncompressed_headers = + std::string uncompressed_headers = SpdyUtils::SerializeUncompressedHeaders(headers_); EXPECT_CALL(delegate_, OnDataReceived(StrEq(uncompressed_headers.data()), uncompressed_headers.size()));
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 56c327c..9f3f3d3 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -134,8 +134,8 @@ clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_)); } if (HasClientSentConnectionOption(config, kPACE) || - (FLAGS_quic_allow_bbr && - HasClientSentConnectionOption(config, kTBBR))) { + FLAGS_quic_enable_pacing || + (FLAGS_quic_allow_bbr && HasClientSentConnectionOption(config, kTBBR))) { EnablePacing(); } if (HasClientSentConnectionOption(config, k1CON)) {
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index c1e6f20..1a907ff 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -1384,6 +1384,20 @@ EXPECT_TRUE(manager_.using_pacing()); } +TEST_F(QuicSentPacketManagerTest, EnablePacingViaFlag) { + EXPECT_FALSE(manager_.using_pacing()); + + // If pacing is enabled via command-line flag, it will be turned on, + // regardless of the contents of the config. + ValueRestore<bool> old_flag(&FLAGS_quic_enable_pacing, true); + QuicConfig config; + EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange()); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, /* using_pacing= */ true)); + manager_.SetFromConfig(config); + + EXPECT_TRUE(manager_.using_pacing()); +} + TEST_F(QuicSentPacketManagerTest, NegotiateReceiveWindowFromOptions) { EXPECT_EQ(kDefaultSocketReceiveBuffer, QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc index e0defd6..64857c0 100644 --- a/net/quic/quic_server_session.cc +++ b/net/quic/quic_server_session.cc
@@ -83,6 +83,11 @@ return; } + // Only send updates when the application has no data to write. + if (HasDataToWrite()) { + return; + } + // If not enough time has passed since the last time we sent an update to the // client, or not enough packets have been sent, then return early. const QuicSentPacketManager& sent_packet_manager =
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h index 43107a0..5614b21 100644 --- a/net/quic/quic_server_session.h +++ b/net/quic/quic_server_session.h
@@ -8,6 +8,7 @@ #define NET_QUIC_QUIC_SERVER_SESSION_H_ #include <set> +#include <string> #include <vector> #include "base/basictypes.h" @@ -67,7 +68,7 @@ // Override base class to process FEC config received from client. void OnConfigNegotiated() override; - void set_serving_region(string serving_region) { + void set_serving_region(std::string serving_region) { serving_region_ = serving_region; } @@ -96,7 +97,7 @@ // Text describing server location. Sent to the client as part of the bandwith // estimate in the source-address token. Optional, can be left empty. - string serving_region_; + std::string serving_region_; // Time at which we send the last SCUP to the client. QuicTime last_scup_time_;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index f05395e..1efefda 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -15,7 +15,9 @@ using base::hash_map; using base::hash_set; using std::make_pair; +using std::map; using std::max; +using std::string; using std::vector; namespace net {
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 7bc743a..3339d42 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h
@@ -7,6 +7,8 @@ #ifndef NET_QUIC_QUIC_SESSION_H_ #define NET_QUIC_QUIC_SESSION_H_ +#include <map> +#include <string> #include <vector> #include "base/compiler_specific.h"
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index d953678..e404929 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc
@@ -5,7 +5,6 @@ #include "net/quic/quic_session.h" #include <set> -#include <vector> #include "base/basictypes.h" #include "base/containers/hash_tables.h" @@ -33,6 +32,7 @@ using base::hash_map; using std::set; +using std::string; using std::vector; using testing::CreateFunctor; using testing::InSequence;
diff --git a/net/quic/quic_spdy_server_stream.h b/net/quic/quic_spdy_server_stream.h index 54506d1..a8bd9f3 100644 --- a/net/quic/quic_spdy_server_stream.h +++ b/net/quic/quic_spdy_server_stream.h
@@ -51,7 +51,7 @@ base::StringPiece body); SpdyHeaderBlock headers_; - string body_; + std::string body_; GURL request_url_; // Buffer into which response header data is read.
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index e7612a0..738326a 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -10,6 +10,7 @@ #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" #include "base/metrics/histogram.h" +#include "base/profiler/scoped_tracker.h" #include "base/rand_util.h" #include "base/stl_util.h" #include "base/strings/string_util.h" @@ -40,9 +41,6 @@ #include "base/win/windows_version.h" #endif -using std::string; -using std::vector; - namespace net { namespace { @@ -294,6 +292,11 @@ } void QuicStreamFactory::Job::OnIOComplete(int rv) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 QuicStreamFactory::Job::OnIOComplete")); + rv = DoLoop(rv); if (rv != ERR_IO_PENDING && !callback_.is_null()) {
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index 153e6cf..ceeaa94 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc
@@ -14,6 +14,7 @@ using std::make_pair; using std::min; using std::numeric_limits; +using std::string; namespace net {
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h index 5da2c0e..025dca4 100644 --- a/net/quic/quic_stream_sequencer.h +++ b/net/quic/quic_stream_sequencer.h
@@ -6,14 +6,12 @@ #define NET_QUIC_QUIC_STREAM_SEQUENCER_H_ #include <map> +#include <string> #include "base/basictypes.h" #include "net/base/iovec.h" #include "net/quic/quic_protocol.h" -using std::map; -using std::string; - namespace net { namespace test { @@ -103,7 +101,7 @@ // frames, in which case we will have to allow receipt of overlapping frames. // Maybe write new frames into a ring buffer, and keep track of consumed // bytes, and gaps. - typedef map<QuicStreamOffset, string> FrameMap; + typedef std::map<QuicStreamOffset, std::string> FrameMap; // Stores buffered frames (maps from sequence number -> frame data as string). FrameMap buffered_frames_;
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 43a105b..8a71c4c 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc
@@ -22,6 +22,7 @@ using std::map; using std::min; using std::pair; +using std::string; using std::vector; using testing::_; using testing::AnyNumber;
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc index 67d347f..8f1f564 100644 --- a/net/quic/quic_time_wait_list_manager.cc +++ b/net/quic/quic_time_wait_list_manager.cc
@@ -27,8 +27,9 @@ namespace { -// Time period for which the connection_id should live in time wait state. -const int kTimeWaitSeconds = 5; +// Time period for which a given connection_id should live in the time-wait +// state. +int64 FLAGS_quic_time_wait_list_seconds = 5; } // namespace @@ -88,7 +89,8 @@ QuicConnectionHelperInterface* helper, const QuicVersionVector& supported_versions) : helper_(helper), - kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), + kTimeWaitPeriod_( + QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)), connection_id_clean_up_alarm_( helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))), writer_(writer), @@ -276,6 +278,7 @@ break; } // This connection_id has lived its age, retire it now. + DVLOG(1) << "Retiring " << it->first << " from the time-wait state."; delete it->second.close_packet; connection_id_map_.erase(it); }
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 116d843..a4b90b7 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -12,6 +12,7 @@ using base::StringPiece; using std::min; +using std::string; namespace net {
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 698fefb..1de6004 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h
@@ -10,6 +10,7 @@ #include <sys/types.h> #include <list> +#include <string> #include "base/basictypes.h" #include "base/memory/ref_counted.h" @@ -67,7 +68,7 @@ // Called to close the entire connection from this end. virtual void CloseConnection(QuicErrorCode error); virtual void CloseConnectionWithDetails(QuicErrorCode error, - const string& details); + const std::string& details); // Returns the effective priority for the stream. This value may change // during the life of the stream. @@ -181,11 +182,11 @@ class ProxyAckNotifierDelegate; struct PendingData { - PendingData(string data_in, + PendingData(std::string data_in, scoped_refptr<ProxyAckNotifierDelegate> delegate_in); ~PendingData(); - string data; + std::string data; // Delegate that should be notified when the pending data is acked. // Can be nullptr. scoped_refptr<ProxyAckNotifierDelegate> delegate;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index d63a5d8..4a77aa0 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc
@@ -21,6 +21,7 @@ using base::StringPiece; using std::min; +using std::string; using testing::CreateFunctor; using testing::InSequence; using testing::Invoke;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc index eef3b80..b45d371 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -9,6 +9,8 @@ #include "net/quic/quic_server_id.h" #include "testing/gtest/include/gtest/gtest.h" +using std::string; + namespace net { MockCryptoClientStream::MockCryptoClientStream(
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 8a8df46..f986d2e 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -154,6 +154,11 @@ } // static +bool QuicConnectionPeer::IsSilentCloseEnabled(QuicConnection* connection) { + return connection->silent_close_enabled_; +} + +// static void QuicConnectionPeer::SwapCrypters(QuicConnection* connection, QuicFramer* framer) { QuicFramerPeer::SwapCrypters(framer, &connection->framer_);
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index d452d43..268b139 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h
@@ -91,6 +91,8 @@ static void SetPeerAddress(QuicConnection* connection, const IPEndPoint& peer_address); + static bool IsSilentCloseEnabled(QuicConnection* connection); + static void SwapCrypters(QuicConnection* connection, QuicFramer* framer); static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection);
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc index 14897b2..7dd7b66 100644 --- a/net/quic/test_tools/quic_session_peer.cc +++ b/net/quic/test_tools/quic_session_peer.cc
@@ -7,6 +7,8 @@ #include "net/quic/quic_session.h" #include "net/quic/reliable_quic_stream.h" +using std::map; + namespace net { namespace test {
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h index e69f6ba..4a88c88 100644 --- a/net/quic/test_tools/quic_session_peer.h +++ b/net/quic/test_tools/quic_session_peer.h
@@ -5,6 +5,8 @@ #ifndef NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_ #define NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_ +#include <map> + #include "net/quic/quic_protocol.h" #include "net/quic/quic_write_blocked_list.h"
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 6b6efe3..980132d 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -304,16 +304,17 @@ const IPEndPoint& peer_address, const QuicEncryptedPacket& packet)); MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error)); - MOCK_METHOD2(SendConnectionCloseWithDetails, void(QuicErrorCode error, - const string& details)); - MOCK_METHOD2(SendConnectionClosePacket, void(QuicErrorCode error, - const string& details)); + MOCK_METHOD2(SendConnectionCloseWithDetails, + void(QuicErrorCode error, const std::string& details)); + MOCK_METHOD2(SendConnectionClosePacket, + void(QuicErrorCode error, const std::string& details)); MOCK_METHOD3(SendRstStream, void(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written)); - MOCK_METHOD3(SendGoAway, void(QuicErrorCode error, - QuicStreamId last_good_stream_id, - const string& reason)); + MOCK_METHOD3(SendGoAway, + void(QuicErrorCode error, + QuicStreamId last_good_stream_id, + const std::string& reason)); MOCK_METHOD1(SendBlocked, void(QuicStreamId id)); MOCK_METHOD2(SendWindowUpdate, void(QuicStreamId id, QuicStreamOffset byte_offset));
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc index f7c69f2..ecf717f 100644 --- a/net/socket/socks_client_socket.cc +++ b/net/socket/socks_client_socket.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/compiler_specific.h" +#include "base/profiler/scoped_tracker.h" #include "base/sys_byteorder.h" #include "net/base/io_buffer.h" #include "net/base/net_log.h" @@ -230,6 +231,11 @@ } void SOCKSClientSocket::OnIOComplete(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 SOCKSClientSocket::OnIOComplete")); + DCHECK_NE(STATE_NONE, next_state_); int rv = DoLoop(result); if (rv != ERR_IO_PENDING) {
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h index 15cef5c..bcc369f 100644 --- a/net/socket/transport_client_socket_pool.h +++ b/net/socket/transport_client_socket_pool.h
@@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/profiler/scoped_tracker.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "net/base/host_port_pair.h" @@ -319,6 +320,11 @@ template <class T> void TransportConnectJobHelper::OnIOComplete(T* job, int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 TransportConnectJobHelper::OnIOComplete")); + result = this->DoLoop(job, result); if (result != ERR_IO_PENDING) job->NotifyDelegateOfCompletion(result); // Deletes |job| and |this|
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc index f3fc575..568507e 100644 --- a/net/spdy/buffered_spdy_framer.cc +++ b/net/spdy/buffered_spdy_framer.cc
@@ -336,7 +336,7 @@ } // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR). -SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id, +SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id, bool is_ack) const { SpdyPingIR ping_ir(unique_id); ping_ir.set_is_ack(is_ack);
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index 1227a42..b8428ce 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h
@@ -194,7 +194,7 @@ SpdyFrame* CreateRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) const; SpdyFrame* CreateSettings(const SettingsMap& values) const; - SpdyFrame* CreatePingFrame(uint32 unique_id, bool is_ack) const; + SpdyFrame* CreatePingFrame(SpdyPingId unique_id, bool is_ack) const; SpdyFrame* CreateGoAway( SpdyStreamId last_accepted_stream_id, SpdyGoAwayStatus status) const;
diff --git a/net/spdy/fuzzing/hpack_fuzz_util.cc b/net/spdy/fuzzing/hpack_fuzz_util.cc index 58f2ec1..29604fe 100644 --- a/net/spdy/fuzzing/hpack_fuzz_util.cc +++ b/net/spdy/fuzzing/hpack_fuzz_util.cc
@@ -107,7 +107,8 @@ // static size_t HpackFuzzUtil::SampleExponential(size_t mean, size_t sanity_bound) { - return std::min<size_t>(-std::log(base::RandDouble()) * mean, sanity_bound); + return std::min(static_cast<size_t>(-std::log(base::RandDouble()) * mean), + sanity_bound); } // static
diff --git a/net/spdy/hpack_huffman_table.cc b/net/spdy/hpack_huffman_table.cc index 9e8f6a1..d9cff25 100644 --- a/net/spdy/hpack_huffman_table.cc +++ b/net/spdy/hpack_huffman_table.cc
@@ -8,6 +8,7 @@ #include <cmath> #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "net/spdy/hpack_input_stream.h" #include "net/spdy/hpack_output_stream.h" @@ -56,10 +57,11 @@ bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, size_t symbol_count) { CHECK(!IsInitialized()); + DCHECK(base::IsValueInRangeForNumericType<uint16>(symbol_count)); std::vector<Symbol> symbols(symbol_count); // Validate symbol id sequence, and copy into |symbols|. - for (size_t i = 0; i != symbol_count; i++) { + for (uint16 i = 0; i < symbol_count; i++) { if (i != input_symbols[i].id) { failed_symbol_id_ = i; return false;
diff --git a/net/spdy/hpack_huffman_table.h b/net/spdy/hpack_huffman_table.h index f776ddd..55352d4 100644 --- a/net/spdy/hpack_huffman_table.h +++ b/net/spdy/hpack_huffman_table.h
@@ -67,7 +67,8 @@ // Prepares HpackHuffmanTable to encode & decode the canonical Huffman // code as determined by the given symbols. Must be called exactly once. // Returns false if the input symbols define an invalid coding, and true - // otherwise. Symbols must be presented in ascending ID order with no gaps. + // otherwise. Symbols must be presented in ascending ID order with no gaps, + // and |symbol_count| must fit in a uint16. bool Initialize(const Symbol* input_symbols, size_t symbol_count); // Returns whether Initialize() has been successfully called.
diff --git a/net/spdy/hpack_huffman_table_test.cc b/net/spdy/hpack_huffman_table_test.cc index f3c09d4..b1da6a8 100644 --- a/net/spdy/hpack_huffman_table_test.cc +++ b/net/spdy/hpack_huffman_table_test.cc
@@ -238,18 +238,12 @@ {bits32("10011000000000000000000000000000"), 8, 6}, // 8th. {bits32("10010000000000000000000000000000"), 5, 7}}; // 7th. EXPECT_TRUE(table_.Initialize(code, arraysize(code))); - - EXPECT_THAT(peer_.code_by_id(), ElementsAre( - bits32("01100000000000000000000000000000"), - bits32("01110000000000000000000000000000"), - bits32("00000000000000000000000000000000"), - bits32("01000000000000000000000000000000"), - bits32("10000000000000000000000000000000"), - bits32("10001000000000000000000000000000"), - bits32("10011000000000000000000000000000"), - bits32("10010000000000000000000000000000"))); - EXPECT_THAT(peer_.length_by_id(), ElementsAre( - 4, 4, 2, 3, 5, 5, 8, 5)); + ASSERT_EQ(arraysize(code), peer_.code_by_id().size()); + ASSERT_EQ(arraysize(code), peer_.length_by_id().size()); + for (size_t i = 0; i < arraysize(code); ++i) { + EXPECT_EQ(code[i].code, peer_.code_by_id()[i]); + EXPECT_EQ(code[i].length, peer_.length_by_id()[i]); + } EXPECT_EQ(1u, peer_.decode_tables().size()); {
diff --git a/net/spdy/spdy_frame_builder.h b/net/spdy/spdy_frame_builder.h index 7aa6db4..bd70977 100644 --- a/net/spdy/spdy_frame_builder.h +++ b/net/spdy/spdy_frame_builder.h
@@ -106,7 +106,7 @@ } bool WriteUInt64(uint64 value) { uint32 upper = htonl(value >> 32); - uint32 lower = htonl(value); + uint32 lower = htonl(static_cast<uint32>(value)); return (WriteBytes(&upper, sizeof(upper)) && WriteBytes(&lower, sizeof(lower))); }
diff --git a/net/spdy/spdy_frame_reader_test.cc b/net/spdy/spdy_frame_reader_test.cc index 90f593b..8db2d99 100644 --- a/net/spdy/spdy_frame_reader_test.cc +++ b/net/spdy/spdy_frame_reader_test.cc
@@ -18,8 +18,8 @@ htons(1), htons(1<<15), }; - SpdyFrameReader frame_reader(reinterpret_cast<const char *>(kFrameData), - arraysize(kFrameData) * sizeof(uint16)); + SpdyFrameReader frame_reader(reinterpret_cast<const char*>(kFrameData), + sizeof(kFrameData)); EXPECT_FALSE(frame_reader.IsDoneReading()); uint16 uint16_val;
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index f1b1de3..990f722 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc
@@ -689,7 +689,7 @@ bool is_control_frame = false; - uint16 control_frame_type_field = + int control_frame_type_field = SpdyConstants::DataFrameType(protocol_version()); // ProcessControlFrameHeader() will set current_frame_type_ to the // correct value if this is a valid control frame. @@ -715,7 +715,9 @@ } // We check control_frame_type_field's validity in // ProcessControlFrameHeader(). - successful_read = reader->ReadUInt16(&control_frame_type_field); + uint16 control_frame_type_field_uint16; + successful_read = reader->ReadUInt16(&control_frame_type_field_uint16); + control_frame_type_field = control_frame_type_field_uint16; } else { reader->Rewind(); successful_read = reader->ReadUInt31(¤t_frame_stream_id_); @@ -735,17 +737,14 @@ bool successful_read = reader->ReadUInt24(&length_field); DCHECK(successful_read); - uint8 control_frame_type_field_uint8 = - SpdyConstants::DataFrameType(protocol_version()); + uint8 control_frame_type_field_uint8; successful_read = reader->ReadUInt8(&control_frame_type_field_uint8); DCHECK(successful_read); // We check control_frame_type_field's validity in // ProcessControlFrameHeader(). control_frame_type_field = control_frame_type_field_uint8; - is_control_frame = (protocol_version() > SPDY3) ? - control_frame_type_field != - SpdyConstants::SerializeFrameType(protocol_version(), DATA) : - control_frame_type_field != 0; + is_control_frame = control_frame_type_field != + SpdyConstants::SerializeFrameType(protocol_version(), DATA); if (is_control_frame) { current_frame_length_ = length_field + GetControlFrameHeaderSize(); @@ -838,7 +837,7 @@ return original_len - len; } -void SpdyFramer::ProcessControlFrameHeader(uint16 control_frame_type_field) { +void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) { DCHECK_EQ(SPDY_NO_ERROR, error_code_); DCHECK_LE(GetControlFrameHeaderSize(), current_frame_buffer_length_); @@ -1191,7 +1190,7 @@ const SpdyMajorVersion spdy_version, const SpdyHeaderBlock* headers) { if (spdy_version < SPDY3) { - frame->WriteUInt16(headers->size()); + frame->WriteUInt16(static_cast<uint16>(headers->size())); } else { frame->WriteUInt32(headers->size()); } @@ -1270,7 +1269,7 @@ char buf[4]; DCHECK_LE(length, sizeof(buf)); for (unsigned i = 1; i <= length; i++) { - buf[length - i] = n; + buf[length - i] = static_cast<char>(n); n >>= 8; } WriteZ(base::StringPiece(buf, length), clas, out); @@ -1489,7 +1488,7 @@ } const bool has_priority = (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0; - uint32 priority = 0; + SpdyPriority priority = 0; if (protocol_version() > SPDY3 && has_priority) { // TODO(jgraettinger): Process dependency rather than ignoring it. reader.Seek(kPriorityDependencyPayloadSize); @@ -2471,7 +2470,7 @@ // which doesn't currently include RST_STREAM payloads. GFE flags have been // commented but left in place to simplify future patching. // Compute the output buffer size, taking opaque data into account. - uint16 expected_length = GetRstStreamMinimumSize(); + size_t expected_length = GetRstStreamMinimumSize(); if (protocol_version() > SPDY3) { expected_length += rst_stream.description().size(); } @@ -2536,6 +2535,9 @@ for (SpdySettingsIR::ValueMap::const_iterator it = values->begin(); it != values->end(); ++it) { + int setting_id = + SpdyConstants::SerializeSettingId(protocol_version(), it->first); + DCHECK_GE(setting_id, 0); if (protocol_version() <= SPDY3) { uint8 setting_flags = 0; if (it->second.persist_value) { @@ -2544,14 +2546,11 @@ if (it->second.persisted) { setting_flags |= SETTINGS_FLAG_PERSISTED; } - SettingsFlagsAndId flags_and_id( - setting_flags, - SpdyConstants::SerializeSettingId(protocol_version(), it->first)); + SettingsFlagsAndId flags_and_id(setting_flags, setting_id); uint32 id_and_flags_wire = flags_and_id.GetWireFormat(protocol_version()); builder.WriteBytes(&id_and_flags_wire, 4); } else { - builder.WriteUInt16(SpdyConstants::SerializeSettingId(protocol_version(), - it->first)); + builder.WriteUInt16(static_cast<uint16>(setting_id)); } builder.WriteUInt32(it->second.value); } @@ -2580,7 +2579,7 @@ const SpdyGoAwayIR& goaway) const { // Compute the output buffer size, take opaque data into account. - uint16 expected_length = GetGoAwayMinimumSize(); + size_t expected_length = GetGoAwayMinimumSize(); if (protocol_version() > SPDY3) { expected_length += goaway.description().size(); } @@ -2639,9 +2638,9 @@ size += headers.padding_payload_len(); } - uint32 priority = headers.priority(); + SpdyPriority priority = static_cast<SpdyPriority>(headers.priority()); if (headers.has_priority()) { - if (priority > GetLowestPriority()) { + if (headers.priority() > GetLowestPriority()) { DLOG(DFATAL) << "Priority out-of-bounds."; priority = GetLowestPriority(); } @@ -2854,13 +2853,15 @@ SpdyFrameBuilder builder(size, protocol_version()); builder.BeginNewFrame(*this, ALTSVC, kNoFlags, altsvc.stream_id()); + // TODO(bnc): http://crbug.com/438263 + // Update the binary format here to the new text-based payload format. builder.WriteUInt32(altsvc.max_age()); builder.WriteUInt16(altsvc.port()); builder.WriteUInt8(0); // Reserved. - builder.WriteUInt8(altsvc.protocol_id().length()); + builder.WriteUInt8(static_cast<uint8>(altsvc.protocol_id().length())); builder.WriteBytes(altsvc.protocol_id().data(), altsvc.protocol_id().length()); - builder.WriteUInt8(altsvc.host().length()); + builder.WriteUInt8(static_cast<uint8>(altsvc.host().length())); builder.WriteBytes(altsvc.host().data(), altsvc.host().length()); builder.WriteBytes(altsvc.origin().data(), altsvc.origin().length()); DCHECK_LT(GetAltSvcMinimumSize(), builder.length()); @@ -3207,7 +3208,7 @@ const SpdyNameValueBlock& name_value_block) const { // Serialize number of headers. if (protocol_version() <= SPDY2) { - builder->WriteUInt16(name_value_block.size()); + builder->WriteUInt16(static_cast<uint16>(name_value_block.size())); } else { builder->WriteUInt32(name_value_block.size()); }
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index dcb2911..8224e9e 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h
@@ -653,7 +653,7 @@ void DeliverHpackBlockAsSpdy3Block(); // Helpers for above internal breakouts from ProcessInput. - void ProcessControlFrameHeader(uint16 control_frame_type_field); + void ProcessControlFrameHeader(int control_frame_type_field); // Always passed exactly 1 setting's worth of data. bool ProcessSetting(const char* data);
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index 2fac61c..2309bda 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc
@@ -18,13 +18,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/platform_test.h" -using base::StringPiece; using std::string; -using std::max; -using std::min; -using std::numeric_limits; -using testing::ElementsAre; -using testing::Pair; using testing::_; namespace net { @@ -368,7 +362,7 @@ bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override { if ((rst_stream_data != NULL) && (len > 0)) { - fin_opaque_data_ += std::string(rst_stream_data, len); + fin_opaque_data_ += string(rst_stream_data, len); } return true; } @@ -478,7 +472,7 @@ // the socket. const size_t kMaxReadSize = 32; size_t bytes_read = - (rand() % min(input_remaining, kMaxReadSize)) + 1; + (rand() % std::min(input_remaining, kMaxReadSize)) + 1; size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); input_remaining -= bytes_processed; input_ptr += bytes_processed; @@ -542,7 +536,7 @@ SpdyStreamId last_push_promise_promised_stream_; int data_bytes_; int fin_frame_count_; // The count of RST_STREAM type frames received. - std::string fin_opaque_data_; + string fin_opaque_data_; int fin_flag_count_; // The count of frames with the FIN flag set. int zero_length_data_frame_count_; // The count of zero-length data frames. int control_frame_header_data_count_; // The count of chunks received. @@ -950,8 +944,8 @@ reinterpret_cast<unsigned char*>(control_frame->data()), control_frame->size()); - EXPECT_THAT(visitor.headers_, ElementsAre( - Pair("name", value))); + EXPECT_THAT(visitor.headers_, + testing::ElementsAre(testing::Pair("name", value))); } TEST_P(SpdyFramerTest, BasicCompression) { @@ -3770,21 +3764,23 @@ SpdyFramer framer(spdy_version_); // Create a GoAway frame that has a few extra bytes at the end. // We create enough overhead to overflow the framer's control frame buffer. - ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize); - const unsigned char length = 1 + SpdyFramer::kControlFrameBufferSize; + ASSERT_LE(SpdyFramer::kControlFrameBufferSize, 250u); + const size_t length = SpdyFramer::kControlFrameBufferSize + 1; const unsigned char kV3FrameData[] = { // Also applies for V2. 0x80, spdy_version_ch_, 0x00, 0x07, - 0x00, 0x00, 0x00, length, + 0x00, 0x00, 0x00, static_cast<unsigned char>(length), 0x00, 0x00, 0x00, 0x00, // Stream ID 0x00, 0x00, 0x00, 0x00, // Status }; // SPDY version 4 and up GOAWAY frames are only bound to a minimal length, // since it may carry opaque data. Verify that minimal length is tested. - const unsigned char less_than_min_length = + ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetControlFrameHeaderSize()); + const size_t less_than_min_length = framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1; + ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max()); const unsigned char kV4FrameData[] = { - 0x00, 0x00, static_cast<uint8>(less_than_min_length), 0x07, + 0x00, 0x00, static_cast<unsigned char>(less_than_min_length), 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Stream Id 0x00, 0x00, 0x00, 0x00, // Status @@ -3793,7 +3789,7 @@ const size_t pad_length = length + framer.GetControlFrameHeaderSize() - (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData)); - string pad('A', pad_length); + string pad(pad_length, 'A'); TestSpdyVisitor visitor(spdy_version_); if (IsSpdy4()) { @@ -3893,7 +3889,7 @@ size_t unframed_data = control_frame->size(); size_t kReadChunkSize = 5; // Read five bytes at a time. while (unframed_data > 0) { - size_t to_read = min(kReadChunkSize, unframed_data); + size_t to_read = std::min(kReadChunkSize, unframed_data); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), to_read); @@ -4294,9 +4290,10 @@ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); EXPECT_EQ(0, visitor.zero_length_data_frame_count_); - EXPECT_THAT(visitor.headers_, ElementsAre( - Pair("cookie", "foo=bar; baz=bing; "), - Pair("name", "value"))); + EXPECT_THAT(visitor.headers_, + testing::ElementsAre( + testing::Pair("cookie", "foo=bar; baz=bing; "), + testing::Pair("name", "value"))); } TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) { @@ -4340,9 +4337,10 @@ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); EXPECT_EQ(1, visitor.zero_length_data_frame_count_); - EXPECT_THAT(visitor.headers_, ElementsAre( - Pair("cookie", "foo=bar; baz=bing; "), - Pair("name", "value"))); + EXPECT_THAT(visitor.headers_, + testing::ElementsAre( + testing::Pair("cookie", "foo=bar; baz=bing; "), + testing::Pair("name", "value"))); } TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) { @@ -4389,9 +4387,10 @@ EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); EXPECT_EQ(0, visitor.zero_length_data_frame_count_); - EXPECT_THAT(visitor.headers_, ElementsAre( - Pair("cookie", "foo=bar; baz=bing; "), - Pair("name", "value"))); + EXPECT_THAT(visitor.headers_, + testing::ElementsAre( + testing::Pair("cookie", "foo=bar; baz=bing; "), + testing::Pair("name", "value"))); } TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) { @@ -4570,8 +4569,8 @@ EXPECT_EQ(1, visitor.headers_frame_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_THAT(visitor.headers_, ElementsAre( - Pair("cookie", "foo=bar"))); + EXPECT_THAT(visitor.headers_, + testing::ElementsAre(testing::Pair("cookie", "foo=bar"))); } TEST_P(SpdyFramerTest, ReadGarbage) { @@ -4860,7 +4859,8 @@ return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -4892,7 +4892,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, DataFrameFlagsV4) { @@ -4903,7 +4903,8 @@ uint8 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED; - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -4940,7 +4941,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, SynStreamFrameFlags) { @@ -4948,7 +4949,8 @@ // SYN_STREAM not supported in SPDY>3 return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -4964,8 +4966,7 @@ syn_stream.set_priority(1); syn_stream.SetHeader("foo", "bar"); scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); - int set_flags = flags; - SetFrameFlags(frame.get(), set_flags, spdy_version_); + SetFrameFlags(frame.get(), flags, spdy_version_); if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { EXPECT_CALL(visitor, OnError(_)); @@ -4994,7 +4995,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, SynReplyFrameFlags) { @@ -5002,7 +5003,8 @@ // SYN_REPLY not supported in SPDY>3 return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5036,11 +5038,12 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, RstStreamFrameFlags) { - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5068,12 +5071,13 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) { if (spdy_version_ > SPDY3) { return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5109,12 +5113,13 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, SettingsFrameFlags) { if (spdy_version_ <= SPDY3) { return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5151,11 +5156,12 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, GoawayFrameFlags) { - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5183,11 +5189,12 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, HeadersFrameFlags) { - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5201,7 +5208,7 @@ } headers_ir.SetHeader("foo", "bar"); scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); - int set_flags = flags; + uint8 set_flags = flags; if (IsSpdy4()) { // TODO(jgraettinger): Add padding to SpdyHeadersIR, // and implement framing. @@ -5266,11 +5273,12 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, PingFrameFlags) { - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5301,11 +5309,12 @@ framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) { - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5333,7 +5342,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { @@ -5341,7 +5350,8 @@ return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<net::test::MockSpdyFramerVisitor> visitor; @@ -5358,8 +5368,7 @@ framer.SerializePushPromise(push_promise)); // TODO(jgraettinger): Add padding to SpdyPushPromiseIR, // and implement framing. - int set_flags = flags & ~HEADERS_FLAG_PADDED; - SetFrameFlags(frame.get(), set_flags, spdy_version_); + SetFrameFlags(frame.get(), flags & ~HEADERS_FLAG_PADDED, spdy_version_); if (flags & ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | HEADERS_FLAG_PADDED)) { EXPECT_CALL(visitor, OnError(_)); @@ -5382,7 +5391,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } TEST_P(SpdyFramerTest, ContinuationFrameFlags) { @@ -5390,7 +5399,8 @@ return; } - for (int flags = 0; flags < 256; ++flags) { + uint8 flags = 0; + do { SCOPED_TRACE(testing::Message() << "Flags " << flags); testing::StrictMock<test::MockSpdyFramerVisitor> visitor; @@ -5438,7 +5448,7 @@ EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) << SpdyFramer::ErrorCodeToString(framer.error_code()); } - } + } while (++flags != 0); } // TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags) @@ -5842,7 +5852,7 @@ size_t unframed_data = control_frame->size(); size_t kReadChunkSize = 5; // Read five bytes at a time. while (unframed_data > 0) { - size_t to_read = min(kReadChunkSize, unframed_data); + size_t to_read = std::min(kReadChunkSize, unframed_data); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(control_frame->data() + framed_data), to_read);
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h index b02c44f..112e928 100644 --- a/net/spdy/spdy_protocol.h +++ b/net/spdy/spdy_protocol.h
@@ -11,6 +11,7 @@ #ifndef NET_SPDY_SPDY_PROTOCOL_H_ #define NET_SPDY_SPDY_PROTOCOL_H_ +#include <limits> #include <map> #include <string> #include <vector> @@ -983,12 +984,8 @@ void set_protocol_id(SpdyProtocolId protocol_id) { protocol_id_ = protocol_id; } - void set_host(std::string host) { - host_ = host; - } - void set_origin(std::string origin) { - origin_ = origin; - } + void set_host(std::string host) { host_ = host; } + void set_origin(std::string origin) { origin_ = origin; } void Visit(SpdyFrameVisitor* visitor) const override;
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 4b91909..a2e239e 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -238,7 +238,7 @@ const char* type, NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); - dict->SetInteger("unique_id", unique_id); + dict->SetInteger("unique_id", static_cast<int>(unique_id)); dict->SetString("type", type); dict->SetBoolean("is_ack", is_ack); return dict; @@ -2922,7 +2922,7 @@ EnqueueSessionWrite(priority, WINDOW_UPDATE, window_update_frame.Pass()); } -void SpdySession::WritePingFrame(uint32 unique_id, bool is_ack) { +void SpdySession::WritePingFrame(SpdyPingId unique_id, bool is_ack) { DCHECK(buffered_spdy_framer_.get()); scoped_ptr<SpdyFrame> ping_frame( buffered_spdy_framer_->CreatePingFrame(unique_id, is_ack));
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 06dfae6..a468dc4 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h
@@ -729,7 +729,7 @@ RequestPriority priority); // Send the PING frame. - void WritePingFrame(uint32 unique_id, bool is_ack); + void WritePingFrame(SpdyPingId unique_id, bool is_ack); // Post a CheckPingStatus call after delay. Don't post if there is already // CheckPingStatus running. @@ -948,7 +948,7 @@ int64 pings_in_flight() const { return pings_in_flight_; } - uint32 next_ping_id() const { return next_ping_id_; } + SpdyPingId next_ping_id() const { return next_ping_id_; } base::TimeTicks last_activity_time() const { return last_activity_time_; } @@ -1085,7 +1085,7 @@ int64 pings_in_flight_; // This is the next ping_id (unique_id) to be sent in PING frame. - uint32 next_ping_id_; + SpdyPingId next_ping_id_; // This is the last time we have sent a PING. base::TimeTicks last_ping_sent_time_;
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index f0765a0..490af6b 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -969,11 +969,14 @@ const char* const extra_headers[], int extra_header_count, int stream_id, - RequestPriority priority) const { + RequestPriority priority, + const HostPortPair& host_port_pair) const { SpdyHeaderBlock block; block[GetMethodKey()] = "CONNECT"; - block[GetPathKey()] = "www.google.com:443"; - block[GetHostKey()] = "www.google.com"; + block[GetPathKey()] = host_port_pair.ToString(); + block[GetHostKey()] = (host_port_pair.port() == 443) + ? host_port_pair.host() + : host_port_pair.ToString(); MaybeAddVersionHeader(&block); AppendToHeaderBlock(extra_headers, extra_header_count, &block); return ConstructSpdySyn(stream_id, block, priority, false, false);
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 0ee59d4..58e1b00 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -436,7 +436,8 @@ SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[], int extra_header_count, int stream_id, - RequestPriority priority) const; + RequestPriority priority, + const HostPortPair& host_port_pair) const; // Constructs a standard SPDY push SYN frame. // |extra_headers| are the extra header-value pairs, which typically
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index f7efc71..0cde019 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -1347,6 +1347,28 @@ server_thread_->Resume(); } +TEST_P(EndToEndTest, EnablePacingViaFlag) { + // When pacing is enabled via command-line flag, it will always be enabled, + // regardless of the config. or the specific congestion-control algorithm. + ValueRestore<bool> old_flag(&FLAGS_quic_enable_pacing, true); + ASSERT_TRUE(Initialize()); + + client_->client()->WaitForCryptoHandshakeConfirmed(); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + ASSERT_EQ(1u, dispatcher->session_map().size()); + const QuicSentPacketManager& client_sent_packet_manager = + client_->client()->session()->connection()->sent_packet_manager(); + const QuicSentPacketManager& server_sent_packet_manager = + *GetSentPacketManagerFromFirstServerSession(); + EXPECT_TRUE(server_sent_packet_manager.using_pacing()); + EXPECT_TRUE(client_sent_packet_manager.using_pacing()); +} + } // namespace } // namespace test } // namespace tools
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index 74874d7..6264be0 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc
@@ -235,6 +235,10 @@ headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1"); QuicSpdyClientStream* stream = CreateReliableClientStream(); DCHECK(stream != nullptr); + if (stream == nullptr) { + LOG(ERROR) << "stream creation failed!"; + break; + } stream->SendRequest(headers, "", true); stream->set_visitor(this); } @@ -317,6 +321,10 @@ session_->connection()->connected(); } +bool QuicClient::goaway_received() const { + return session_ != nullptr && session_->goaway_received(); +} + QuicConnectionId QuicClient::GenerateConnectionId() { return QuicRandom::GetInstance()->RandUint64(); }
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index 6bf87f9..c095a4d 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h
@@ -44,7 +44,7 @@ virtual ~ResponseListener() {} virtual void OnCompleteResponse(QuicStreamId id, const BalsaHeaders& response_headers, - const string& response_body) = 0; + const std::string& response_body) = 0; }; // Create a quic client, which will have events managed by an externally owned @@ -120,6 +120,7 @@ QuicClientSession* session() { return session_.get(); } bool connected() const; + bool goaway_received() const; void set_bind_to_address(IPAddressNumber address) { bind_to_address_ = address; @@ -142,7 +143,7 @@ server_id_ = server_id; } - void SetUserAgentID(const string& user_agent_id) { + void SetUserAgentID(const std::string& user_agent_id) { crypto_config_.set_user_agent_id(user_agent_id); }
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 45cddb0..fc1e10d 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -29,6 +29,7 @@ using net::test::ValueRestore; using net::tools::test::MockConnection; using std::make_pair; +using std::string; using testing::DoAll; using testing::InSequence; using testing::Invoke;
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc index 9db2365..6e64da5 100644 --- a/net/tools/quic/quic_server_session.cc +++ b/net/tools/quic/quic_server_session.cc
@@ -84,6 +84,11 @@ return; } + // Only send updates when the application has no data to write. + if (HasDataToWrite()) { + return; + } + // If not enough time has passed since the last time we sent an update to the // client, or not enough packets have been sent, then return early. const QuicSentPacketManager& sent_packet_manager =
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h index 603ad35..81cae12 100644 --- a/net/tools/quic/quic_server_session.h +++ b/net/tools/quic/quic_server_session.h
@@ -8,6 +8,7 @@ #define NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_ #include <set> +#include <string> #include <vector> #include "base/basictypes.h" @@ -68,7 +69,7 @@ // Override base class to process FEC config received from client. void OnConfigNegotiated() override; - void set_serving_region(string serving_region) { + void set_serving_region(std::string serving_region) { serving_region_ = serving_region; } @@ -97,7 +98,7 @@ // Text describing server location. Sent to the client as part of the bandwith // estimate in the source-address token. Optional, can be left empty. - string serving_region_; + std::string serving_region_; // Time at which we send the last SCUP to the client. QuicTime last_scup_time_;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index 4705c05..c8f8bce 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc
@@ -37,6 +37,7 @@ using net::test::kClientDataStreamId2; using net::test::kClientDataStreamId3; using net::test::kClientDataStreamId4; +using std::string; using testing::StrictMock; using testing::_; @@ -305,7 +306,8 @@ } // Test that bandwidth estimate updates are sent to the client, only after the - // bandwidth estimate has changes sufficiently, and enough time has passed. + // bandwidth estimate has changes sufficiently, and enough time has passed, + // and we don't have any other data to write. int32 bandwidth_estimate_kbytes_per_second = 123; int32 max_bandwidth_estimate_kbytes_per_second = 134; @@ -332,6 +334,10 @@ QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate( &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second, max_bandwidth_estimate_timestamp); + // Queue up some pending data. + session_->MarkWriteBlocked(kCryptoStreamId, + QuicWriteBlockedList::kHighestPriority); + EXPECT_TRUE(session_->HasDataToWrite()); // There will be no update sent yet - not enough time has passed. QuicTime now = QuicTime::Zero(); @@ -351,6 +357,11 @@ kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms)); session_->OnCongestionWindowChange(now); + // The connection no longer has pending data to be written. + session_->OnCanWrite(); + EXPECT_FALSE(session_->HasDataToWrite()); + session_->OnCongestionWindowChange(now); + // Bandwidth estimate has now changed sufficiently, enough time has passed, // and enough packets have been sent. QuicConnectionPeer::SetSequenceNumberOfLastSentPacket(
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc index 3ac0bf3..0eb1185 100644 --- a/net/tools/quic/quic_socket_utils.cc +++ b/net/tools/quic/quic_socket_utils.cc
@@ -23,7 +23,7 @@ namespace tools { // static -IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr *hdr) { +IPAddressNumber QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) { if (hdr->msg_controllen > 0) { for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr; @@ -51,11 +51,10 @@ } // static -bool QuicSocketUtils::GetOverflowFromMsghdr( - struct msghdr *hdr, - QuicPacketCount *dropped_packets) { +bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr, + QuicPacketCount* dropped_packets) { if (hdr->msg_controllen > 0) { - struct cmsghdr *cmsg; + struct cmsghdr* cmsg; for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr; cmsg = CMSG_NXTHDR(hdr, cmsg)) { @@ -103,7 +102,7 @@ QuicPacketCount* dropped_packets, IPAddressNumber* self_address, IPEndPoint* peer_address) { - CHECK(peer_address != nullptr); + DCHECK(peer_address != nullptr); const int kSpaceForOverflowAndIp = CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)); char cbuf[kSpaceForOverflowAndIp]; @@ -119,7 +118,7 @@ hdr.msg_iovlen = 1; hdr.msg_flags = 0; - struct cmsghdr *cmsg = (struct cmsghdr *) cbuf; + struct cmsghdr* cmsg = (struct cmsghdr*)cbuf; cmsg->cmsg_len = arraysize(cbuf); hdr.msg_control = cmsg; hdr.msg_controllen = arraysize(cbuf); @@ -209,7 +208,7 @@ } else { hdr.msg_control = cbuf; hdr.msg_controllen = kSpaceForIp; - cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr); + cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); SetIpInfoInCmsg(self_address, cmsg); hdr.msg_controllen = cmsg->cmsg_len; }
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h index 41d3b93..2c8fe43 100644 --- a/net/tools/quic/quic_socket_utils.h +++ b/net/tools/quic/quic_socket_utils.h
@@ -24,12 +24,12 @@ // If the msghdr contains IP_PKTINFO or IPV6_PKTINFO, this will return the // IPAddressNumber in that header. Returns an uninitialized IPAddress on // failure. - static IPAddressNumber GetAddressFromMsghdr(struct msghdr *hdr); + static IPAddressNumber GetAddressFromMsghdr(struct msghdr* hdr); // If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets // to the correct value and return true. Otherwise it will return false. - static bool GetOverflowFromMsghdr(struct msghdr *hdr, - QuicPacketCount *dropped_packets); + static bool GetOverflowFromMsghdr(struct msghdr* hdr, + QuicPacketCount* dropped_packets); // Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on // address_family. Returns the return code from setsockopt.
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index 090e2da..94ba5aa 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -16,6 +16,7 @@ using net::test::DefaultQuicConfig; using net::test::SupportedVersions; +using std::string; using testing::StrictMock; using testing::TestWithParam;
diff --git a/net/tools/quic/quic_spdy_server_stream.h b/net/tools/quic/quic_spdy_server_stream.h index feb809f..6fa1114 100644 --- a/net/tools/quic/quic_spdy_server_stream.h +++ b/net/tools/quic/quic_spdy_server_stream.h
@@ -52,7 +52,7 @@ base::StringPiece body); BalsaHeaders headers_; - string body_; + std::string body_; // Buffer into which response header data is read. scoped_refptr<GrowableIOBuffer> read_buf_;
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index f54a465..fba4e87 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -28,8 +28,9 @@ namespace { -// Time period for which the connection_id should live in time wait state. -const int kTimeWaitSeconds = 5; +// Time period for which a given connection_id should live in the time-wait +// state. +int64 FLAGS_quic_time_wait_list_seconds = 5; } // namespace @@ -90,7 +91,8 @@ EpollServer* epoll_server, const QuicVersionVector& supported_versions) : epoll_server_(epoll_server), - kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), + kTimeWaitPeriod_( + QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)), connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)), clock_(epoll_server_), writer_(writer), @@ -282,6 +284,7 @@ break; } // This connection_id has lived its age, retire it now. + DVLOG(1) << "Retiring " << it->first << " from the time-wait state."; delete it->second.close_packet; connection_id_map_.erase(it); }
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h index 842d70e..6dcb1b9 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -6,6 +6,7 @@ #define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ #include <list> +#include <string> #include "base/basictypes.h" #include "base/logging.h" @@ -123,7 +124,7 @@ QuicTime send_time); ~DelayedWrite(); - string buffer; + std::string buffer; const IPAddressNumber self_address; const IPEndPoint peer_address; QuicTime send_time;
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index a1dea9e..79224ba 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -63,11 +63,11 @@ public QuicDataStream::Visitor { public: QuicTestClient(IPEndPoint server_address, - const string& server_hostname, + const std::string& server_hostname, bool secure, const QuicVersionVector& supported_versions); QuicTestClient(IPEndPoint server_address, - const string& server_hostname, + const std::string& server_hostname, bool secure, const QuicConfig& config, const QuicVersionVector& supported_versions); @@ -80,18 +80,18 @@ void ExpectCertificates(bool on); // Sets the |user_agent_id| of the |client_|. - void SetUserAgentID(const string& user_agent_id); + void SetUserAgentID(const std::string& user_agent_id); // Wraps data in a quic packet and sends it. - ssize_t SendData(string data, bool last_data); + ssize_t SendData(std::string data, bool last_data); // From SimpleClient // Clears any outstanding state and sends a simple GET of 'uri' to the // server. Returns 0 if the request failed and no bytes were written. - ssize_t SendRequest(const string& uri) override; + ssize_t SendRequest(const std::string& uri) override; ssize_t SendMessage(const HTTPMessage& message) override; - string SendCustomSynchronousRequest(const HTTPMessage& message) override; - string SendSynchronousRequest(const string& uri) override; + std::string SendCustomSynchronousRequest(const HTTPMessage& message) override; + std::string SendSynchronousRequest(const std::string& uri) override; void Connect() override; void ResetConnection() override; void Disconnect() override; @@ -111,13 +111,13 @@ bool buffer_body() const override; void set_buffer_body(bool buffer_body) override; bool ServerInLameDuckMode() const override; - const string& response_body() override; + const std::string& response_body() override; bool connected() const override; // These functions are all unimplemented functions from SimpleClient, and log // DFATAL if called by users of SimpleClient. ssize_t SendAndWaitForResponse(const void* buffer, size_t size) override; void Bind(IPEndPoint* local_address) override; - string SerializeMessage(const HTTPMessage& message) override; + std::string SerializeMessage(const HTTPMessage& message) override; IPAddressNumber bind_to_address() const override; void set_bind_to_address(IPAddressNumber address) override; const IPEndPoint& address() const override; @@ -143,7 +143,7 @@ // cert_common_name returns the common name value of the server's certificate, // or the empty string if no certificate was presented. - const string& cert_common_name() const; + const std::string& cert_common_name() const; // Get the server config map. QuicTagValueMap GetServerConfig() const; @@ -178,7 +178,7 @@ bool response_headers_complete_; BalsaHeaders headers_; QuicPriority priority_; - string response_; + std::string response_; uint64 bytes_read_; uint64 bytes_written_; // The number of uncompressed HTTP header bytes received.
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h index d70b22d..202edf3 100644 --- a/net/tools/quic/test_tools/quic_test_utils.h +++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -29,7 +29,7 @@ namespace test { static const QuicConnectionId kTestConnectionId = 42; -static const int kTestPort = 123; +static const uint16 kTestPort = 123; static const uint32 kInitialStreamFlowControlWindowForTest = 32 * 1024; // 32 KB static const uint32 kInitialSessionFlowControlWindowForTest =
diff --git a/net/udp/udp_client_socket.cc b/net/udp/udp_client_socket.cc index f6f904a..9cdaace 100644 --- a/net/udp/udp_client_socket.cc +++ b/net/udp/udp_client_socket.cc
@@ -4,6 +4,7 @@ #include "net/udp/udp_client_socket.h" +#include "net/base/net_errors.h" #include "net/base/net_log.h" namespace net { @@ -19,6 +20,9 @@ } int UDPClientSocket::Connect(const IPEndPoint& address) { + int rv = socket_.Open(address.GetFamily()); + if (rv != OK) + return rv; return socket_.Connect(address); }
diff --git a/net/udp/udp_server_socket.cc b/net/udp/udp_server_socket.cc index 796c04d..4653f71 100644 --- a/net/udp/udp_server_socket.cc +++ b/net/udp/udp_server_socket.cc
@@ -4,6 +4,7 @@ #include "net/udp/udp_server_socket.h" +#include "net/base/net_errors.h" #include "net/base/rand_callback.h" namespace net { @@ -13,13 +14,35 @@ : socket_(DatagramSocket::DEFAULT_BIND, RandIntCallback(), net_log, - source) { + source), + allow_address_reuse_(false), + allow_broadcast_(false) { } UDPServerSocket::~UDPServerSocket() { } int UDPServerSocket::Listen(const IPEndPoint& address) { + int rv = socket_.Open(address.GetFamily()); + if (rv != OK) + return rv; + + if (allow_address_reuse_) { + rv = socket_.AllowAddressReuse(); + if (rv != OK) { + socket_.Close(); + return rv; + } + } + + if (allow_broadcast_) { + rv = socket_.SetBroadcast(true); + if (rv != OK) { + socket_.Close(); + return rv; + } + } + return socket_.Bind(address); } @@ -62,11 +85,11 @@ } void UDPServerSocket::AllowAddressReuse() { - socket_.AllowAddressReuse(); + allow_address_reuse_ = true; } void UDPServerSocket::AllowBroadcast() { - socket_.AllowBroadcast(); + allow_broadcast_ = true; } int UDPServerSocket::JoinGroup(const IPAddressNumber& group_address) const {
diff --git a/net/udp/udp_server_socket.h b/net/udp/udp_server_socket.h index 77ca86d..0799105 100644 --- a/net/udp/udp_server_socket.h +++ b/net/udp/udp_server_socket.h
@@ -49,6 +49,8 @@ private: UDPSocket socket_; + bool allow_address_reuse_; + bool allow_broadcast_; DISALLOW_COPY_AND_ASSIGN(UDPServerSocket); };
diff --git a/net/udp/udp_socket.h b/net/udp/udp_socket.h index 97a4bc5..2ae4b16 100644 --- a/net/udp/udp_socket.h +++ b/net/udp/udp_socket.h
@@ -21,18 +21,20 @@ // Client form: // In this case, we're connecting to a specific server, so the client will // usually use: -// Connect(address) // Connect to a UDP server -// Read/Write // Reads/Writes all go to a single destination +// Open(address_family) // Open a socket. +// Connect(address) // Connect to a UDP server +// Read/Write // Reads/Writes all go to a single destination // // Server form: // In this case, we want to read/write to many clients which are connecting // to this server. First the server 'binds' to an addres, then we read from // clients and write responses to them. // Example: -// Bind(address/port) // Binds to port for reading from clients -// RecvFrom/SendTo // Each read can come from a different client -// // Writes need to be directed to a specific -// // address. +// Open(address_family) // Open a socket. +// Bind(address/port) // Binds to port for reading from clients +// RecvFrom/SendTo // Each read can come from a different client +// // Writes need to be directed to a specific +// // address. #if defined(OS_WIN) typedef UDPSocketWin UDPSocket; #elif defined(OS_POSIX)
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc index 2dffff3..8dd102a 100644 --- a/net/udp/udp_socket_libevent.cc +++ b/net/udp/udp_socket_libevent.cc
@@ -67,6 +67,7 @@ const net::NetLog::Source& source) : socket_(kInvalidSocket), addr_family_(0), + is_connected_(false), socket_options_(SOCKET_OPTION_MULTICAST_LOOP), multicast_interface_(0), multicast_time_to_live_(1), @@ -89,10 +90,26 @@ net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); } +int UDPSocketLibevent::Open(AddressFamily address_family) { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(socket_, kInvalidSocket); + + addr_family_ = ConvertAddressFamily(address_family); + socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); + if (socket_ == kInvalidSocket) + return MapSystemError(errno); + if (SetNonBlocking(socket_)) { + const int err = MapSystemError(errno); + Close(); + return err; + } + return OK; +} + void UDPSocketLibevent::Close() { DCHECK(CalledOnValidThread()); - if (!is_connected()) + if (socket_ == kInvalidSocket) return; // Zero out any pending read/write callback state. @@ -115,6 +132,7 @@ socket_ = kInvalidSocket; addr_family_ = 0; + is_connected_ = false; } int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { @@ -243,12 +261,12 @@ } int UDPSocketLibevent::Connect(const IPEndPoint& address) { + DCHECK_NE(socket_, kInvalidSocket); net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, CreateNetLogUDPConnectCallback(&address)); int rv = InternalConnect(address); - if (rv != OK) - Close(); net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); + is_connected_ = (rv == OK); return rv; } @@ -256,16 +274,13 @@ DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); DCHECK(!remote_address_.get()); - int addr_family = address.GetSockAddrFamily(); - int rv = CreateSocket(addr_family); - if (rv < 0) - return rv; + int rv = 0; if (bind_type_ == DatagramSocket::RANDOM_BIND) { // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, // representing INADDR_ANY or in6addr_any. - size_t addr_size = - addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize; + size_t addr_size = address.GetSockAddrFamily() == AF_INET ? + kIPv4AddressSize : kIPv6AddressSize; IPAddressNumber addr_any(addr_size); rv = RandomBind(addr_any); } @@ -273,79 +288,79 @@ if (rv < 0) { UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); - Close(); return rv; } SockaddrStorage storage; - if (!address.ToSockAddr(storage.addr, &storage.addr_len)) { - Close(); + if (!address.ToSockAddr(storage.addr, &storage.addr_len)) return ERR_ADDRESS_INVALID; - } rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); - if (rv < 0) { - // Close() may change the current errno. Map errno beforehand. - int result = MapSystemError(errno); - Close(); - return result; - } + if (rv < 0) + return MapSystemError(errno); remote_address_.reset(new IPEndPoint(address)); return rv; } int UDPSocketLibevent::Bind(const IPEndPoint& address) { + DCHECK_NE(socket_, kInvalidSocket); DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); - int rv = CreateSocket(address.GetSockAddrFamily()); + + int rv = SetMulticastOptions(); if (rv < 0) return rv; - rv = SetSocketOptions(); - if (rv < 0) { - Close(); - return rv; - } rv = DoBind(address); - if (rv < 0) { - Close(); + if (rv < 0) return rv; - } + + is_connected_ = true; local_address_.reset(); return rv; } int UDPSocketLibevent::SetReceiveBufferSize(int32 size) { + DCHECK_NE(socket_, kInvalidSocket); DCHECK(CalledOnValidThread()); int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&size), sizeof(size)); - int last_error = errno; - DCHECK(!rv) << "Could not set socket receive buffer size: " << last_error; - return rv == 0 ? OK : MapSystemError(last_error); + return rv == 0 ? OK : MapSystemError(errno); } int UDPSocketLibevent::SetSendBufferSize(int32 size) { + DCHECK_NE(socket_, kInvalidSocket); DCHECK(CalledOnValidThread()); int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&size), sizeof(size)); - int last_error = errno; - DCHECK(!rv) << "Could not set socket send buffer size: " << last_error; - return rv == 0 ? OK : MapSystemError(last_error); + return rv == 0 ? OK : MapSystemError(errno); } -void UDPSocketLibevent::AllowAddressReuse() { +int UDPSocketLibevent::AllowAddressReuse() { + DCHECK_NE(socket_, kInvalidSocket); DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); - - socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; + int true_value = 1; + int rv = setsockopt( + socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value)); + return rv == 0 ? OK : MapSystemError(errno); } -void UDPSocketLibevent::AllowBroadcast() { +int UDPSocketLibevent::SetBroadcast(bool broadcast) { + DCHECK_NE(socket_, kInvalidSocket); DCHECK(CalledOnValidThread()); - DCHECK(!is_connected()); - - socket_options_ |= SOCKET_OPTION_BROADCAST; + int value = broadcast ? 1 : 0; + int rv; +#if defined(OS_MACOSX) + // SO_REUSEPORT on OSX permits multiple processes to each receive + // UDP multicast or broadcast datagrams destined for the bound + // port. + rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)); +#else + rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); +#endif // defined(OS_MACOSX) + return rv == 0 ? OK : MapSystemError(errno); } void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) { @@ -418,19 +433,6 @@ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); } -int UDPSocketLibevent::CreateSocket(int addr_family) { - addr_family_ = addr_family; - socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); - if (socket_ == kInvalidSocket) - return MapSystemError(errno); - if (SetNonBlocking(socket_)) { - const int err = MapSystemError(errno); - Close(); - return err; - } - return OK; -} - void UDPSocketLibevent::DidCompleteWrite() { int result = InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); @@ -518,30 +520,7 @@ return result; } -int UDPSocketLibevent::SetSocketOptions() { - int true_value = 1; - if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { - int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, - sizeof(true_value)); - if (rv < 0) - return MapSystemError(errno); - } - if (socket_options_ & SOCKET_OPTION_BROADCAST) { - int rv; -#if defined(OS_MACOSX) - // SO_REUSEPORT on OSX permits multiple processes to each receive - // UDP multicast or broadcast datagrams destined for the bound - // port. - rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, - sizeof(true_value)); -#else - rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, - sizeof(true_value)); -#endif // defined(OS_MACOSX) - if (rv < 0) - return MapSystemError(errno); - } - +int UDPSocketLibevent::SetMulticastOptions() { if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { int rv; if (addr_family_ == AF_INET) {
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h index 2ac564d..a434bb9 100644 --- a/net/udp/udp_socket_libevent.h +++ b/net/udp/udp_socket_libevent.h
@@ -9,6 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/threading/non_thread_safe.h" +#include "net/base/address_family.h" #include "net/base/completion_callback.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" @@ -28,22 +29,28 @@ const net::NetLog::Source& source); virtual ~UDPSocketLibevent(); - // Connect the socket to connect with a certain |address|. + // Opens the socket. + // Returns a net error code. + int Open(AddressFamily address_family); + + // Connects the socket to connect with a certain |address|. + // Should be called after Open(). // Returns a net error code. int Connect(const IPEndPoint& address); - // Bind the address/port for this socket to |address|. This is generally - // only used on a server. + // Binds the address/port for this socket to |address|. This is generally + // only used on a server. Should be called after Open(). // Returns a net error code. int Bind(const IPEndPoint& address); - // Close the socket. + // Closes the socket. + // TODO(rvargas, hidehiko): Disallow re-Open() after Close(). void Close(); - // Copy the remote udp address into |address| and return a network error code. + // Copies the remote udp address into |address| and returns a net error code. int GetPeerAddress(IPEndPoint* address) const; - // Copy the local udp address into |address| and return a network error code. + // Copies the local udp address into |address| and returns a net error code. // (similar to getsockname) int GetLocalAddress(IPEndPoint* address) const; @@ -51,17 +58,17 @@ // Multiple outstanding read requests are not supported. // Full duplex mode (reading and writing at the same time) is supported - // Read from the socket. + // Reads from the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - // Write to the socket. + // Writes to the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - // Read from a socket and receive sender address information. + // Reads from a socket and receive sender address information. // |buf| is the buffer to read data into. // |buf_len| is the maximum amount of data to read. // |address| is a buffer provided by the caller for receiving the sender @@ -79,7 +86,7 @@ IPEndPoint* address, const CompletionCallback& callback); - // Send to a socket with a particular destination. + // Sends to a socket with a particular destination. // |buf| is the buffer to send // |buf_len| is the number of bytes to send // |address| is the recipient address. @@ -93,60 +100,63 @@ const IPEndPoint& address, const CompletionCallback& callback); - // Set the receive buffer size (in bytes) for the socket. + // Sets the receive buffer size (in bytes) for the socket. + // Returns a net error code. int SetReceiveBufferSize(int32 size); - // Set the send buffer size (in bytes) for the socket. + // Sets the send buffer size (in bytes) for the socket. + // Returns a net error code. int SetSendBufferSize(int32 size); // Returns true if the socket is already connected or bound. - bool is_connected() const { return socket_ != kInvalidSocket; } + bool is_connected() const { return is_connected_; } const BoundNetLog& NetLog() const { return net_log_; } // Sets corresponding flags in |socket_options_| to allow the socket // to share the local address to which the socket will be bound with - // other processes. Should be called before Bind(). - void AllowAddressReuse(); + // other processes. Should be called between Open() and Bind(). + // Returns a net error code. + int AllowAddressReuse(); - // Sets corresponding flags in |socket_options_| to allow sending - // and receiving packets to and from broadcast addresses. Should be - // called before Bind(). - void AllowBroadcast(); + // Sets corresponding flags in |socket_options_| to allow or disallow sending + // and receiving packets to and from broadcast addresses. + // Returns a net error code. + int SetBroadcast(bool broadcast); - // Join the multicast group. + // Joins the multicast group. // |group_address| is the group address to join, could be either // an IPv4 or IPv6 address. - // Return a network error code. + // Returns a net error code. int JoinGroup(const IPAddressNumber& group_address) const; - // Leave the multicast group. + // Leaves the multicast group. // |group_address| is the group address to leave, could be either // an IPv4 or IPv6 address. If the socket hasn't joined the group, // it will be ignored. // It's optional to leave the multicast group before destroying // the socket. It will be done by the OS. - // Return a network error code. + // Returns a net error code. int LeaveGroup(const IPAddressNumber& group_address) const; - // Set interface to use for multicast. If |interface_index| set to 0, default - // interface is used. + // Sets interface to use for multicast. If |interface_index| set to 0, + // default interface is used. // Should be called before Bind(). - // Returns a network error code. + // Returns a net error code. int SetMulticastInterface(uint32 interface_index); - // Set the time-to-live option for UDP packets sent to the multicast + // Sets the time-to-live option for UDP packets sent to the multicast // group address. The default value of this option is 1. // Cannot be negative or more than 255. // Should be called before Bind(). - // Return a network error code. + // Returns a net error code. int SetMulticastTimeToLive(int time_to_live); - // Set the loopback flag for UDP socket. If this flag is true, the host + // Sets the loopback flag for UDP socket. If this flag is true, the host // will receive packets sent to the joined group from itself. // The default value of this option is true. // Should be called before Bind(). - // Return a network error code. + // Returns a net error code. // // Note: the behavior of |SetMulticastLoopbackMode| is slightly // different between Windows and Unix-like systems. The inconsistency only @@ -158,9 +168,9 @@ // other applications on the same host. See MSDN: http://goo.gl/6vqbj int SetMulticastLoopbackMode(bool loopback); - // Set the differentiated services flags on outgoing packets. May not + // Sets the differentiated services flags on outgoing packets. May not // do anything on some platforms. - // Return a network error code. + // Returns a net error code. int SetDiffServCodePoint(DiffServCodePoint dscp); // Resets the thread to be used for thread-safety checks. @@ -168,9 +178,7 @@ private: enum SocketOptions { - SOCKET_OPTION_REUSE_ADDRESS = 1 << 0, - SOCKET_OPTION_BROADCAST = 1 << 1, - SOCKET_OPTION_MULTICAST_LOOP = 1 << 2 + SOCKET_OPTION_MULTICAST_LOOP = 1 << 0 }; class ReadWatcher : public base::MessageLoopForIO::Watcher { @@ -218,9 +226,6 @@ const sockaddr* addr) const; void LogWrite(int result, const char* bytes, const IPEndPoint* address) const; - // Returns the OS error code (or 0 on success). - int CreateSocket(int addr_family); - // Same as SendTo(), except that address is passed by pointer // instead of by reference. It is called from Write() with |address| // set to NULL. @@ -235,13 +240,14 @@ // Applies |socket_options_| to |socket_|. Should be called before // Bind(). - int SetSocketOptions(); + int SetMulticastOptions(); int DoBind(const IPEndPoint& address); // Binds to a random port on |address|. int RandomBind(const IPAddressNumber& address); int socket_; int addr_family_; + bool is_connected_; // Bitwise-or'd combination of SocketOptions. Specifies the set of // options that should be applied to |socket_| before Bind(). @@ -250,7 +256,7 @@ // Multicast interface. uint32 multicast_interface_; - // Multicast socket options cached for SetSocketOption. + // Multicast socket options cached for SetMulticastOption. // Cannot be used after Bind(). int multicast_time_to_live_;
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc index 8282596..c92bf2b 100644 --- a/net/udp/udp_socket_unittest.cc +++ b/net/udp/udp_socket_unittest.cc
@@ -353,7 +353,9 @@ base::Bind(&PrivilegedRand), NULL, NetLog::Source())); - int rv = socket->Connect(peer_address); + int rv = socket->Open(peer_address.GetFamily()); + EXPECT_EQ(OK, rv); + rv = socket->Connect(peer_address); // Connect should have failed since we couldn't bind to that port, EXPECT_NE(OK, rv); // Make sure that UDPSocket actually closed the socket. @@ -550,6 +552,7 @@ RandIntCallback(), NULL, NetLog::Source()); + EXPECT_EQ(OK, socket.Open(bind_address.GetFamily())); EXPECT_EQ(OK, socket.Bind(bind_address)); EXPECT_EQ(OK, socket.JoinGroup(group_ip)); // Joining group multiple times. @@ -578,6 +581,7 @@ EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1)); EXPECT_EQ(OK, socket.SetMulticastInterface(0)); + EXPECT_EQ(OK, socket.Open(bind_address.GetFamily())); EXPECT_EQ(OK, socket.Bind(bind_address)); EXPECT_NE(OK, socket.SetMulticastLoopbackMode(false)); @@ -598,7 +602,10 @@ NetLog::Source()); // We need a real IP, but we won't actually send anything to it. CreateUDPAddress("8.8.8.8", 9999, &bind_address); - int rv = client.Connect(bind_address); + int rv = client.Open(bind_address.GetFamily()); + EXPECT_EQ(OK, rv); + + rv = client.Connect(bind_address); if (rv != OK) { // Let's try localhost then.. CreateUDPAddress("127.0.0.1", 9999, &bind_address); @@ -705,6 +712,10 @@ NetLog::Source()); int rv = client.SetDiffServCodePoint(DSCP_AF41); EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, rv); + + rv = client.Open(bind_address.GetFamily()); + EXPECT_EQ(OK, rv); + rv = client.Connect(bind_address); EXPECT_EQ(OK, rv);
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc index 7be97e8..2f5549f 100644 --- a/net/udp/udp_socket_win.cc +++ b/net/udp/udp_socket_win.cc
@@ -255,6 +255,7 @@ const net::NetLog::Source& source) : socket_(INVALID_SOCKET), addr_family_(0), + is_connected_(false), socket_options_(SOCKET_OPTION_MULTICAST_LOOP), multicast_interface_(0), multicast_time_to_live_(1), @@ -276,10 +277,22 @@ net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); } +int UDPSocketWin::Open(AddressFamily address_family) { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(socket_, INVALID_SOCKET); + + addr_family_ = ConvertAddressFamily(address_family); + socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP); + if (socket_ == INVALID_SOCKET) + return MapSystemError(WSAGetLastError()); + core_ = new Core(this); + return OK; +} + void UDPSocketWin::Close() { DCHECK(CalledOnValidThread()); - if (!is_connected()) + if (socket_ == INVALID_SOCKET) return; if (qos_handle_) { @@ -297,6 +310,7 @@ base::TimeTicks::Now() - start_time); socket_ = INVALID_SOCKET; addr_family_ = 0; + is_connected_ = false; core_->Detach(); core_ = NULL; @@ -407,28 +421,25 @@ } int UDPSocketWin::Connect(const IPEndPoint& address) { + DCHECK_NE(socket_, INVALID_SOCKET); net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, CreateNetLogUDPConnectCallback(&address)); int rv = InternalConnect(address); - if (rv != OK) - Close(); net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); + is_connected_ = (rv == OK); return rv; } int UDPSocketWin::InternalConnect(const IPEndPoint& address) { DCHECK(!is_connected()); DCHECK(!remote_address_.get()); - int addr_family = address.GetSockAddrFamily(); - int rv = CreateSocket(addr_family); - if (rv < 0) - return rv; + int rv = 0; if (bind_type_ == DatagramSocket::RANDOM_BIND) { // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, // representing INADDR_ANY or in6addr_any. - size_t addr_size = - addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize; + size_t addr_size = (address.GetSockAddrFamily() == AF_INET) ? + kIPv4AddressSize : kIPv6AddressSize; IPAddressNumber addr_any(addr_size); rv = RandomBind(addr_any); } @@ -436,7 +447,6 @@ if (rv < 0) { UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); - Close(); return rv; } @@ -445,46 +455,32 @@ return ERR_ADDRESS_INVALID; rv = connect(socket_, storage.addr, storage.addr_len); - if (rv < 0) { - // Close() may change the last error. Map it beforehand. - int result = MapSystemError(WSAGetLastError()); - Close(); - return result; - } + if (rv < 0) + return MapSystemError(WSAGetLastError()); remote_address_.reset(new IPEndPoint(address)); return rv; } int UDPSocketWin::Bind(const IPEndPoint& address) { + DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(!is_connected()); - int rv = CreateSocket(address.GetSockAddrFamily()); + + int rv = SetMulticastOptions(); if (rv < 0) return rv; - rv = SetSocketOptions(); - if (rv < 0) { - Close(); - return rv; - } + rv = DoBind(address); - if (rv < 0) { - Close(); + if (rv < 0) return rv; - } + local_address_.reset(); + is_connected_ = true; return rv; } -int UDPSocketWin::CreateSocket(int addr_family) { - addr_family_ = addr_family; - socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP); - if (socket_ == INVALID_SOCKET) - return MapSystemError(WSAGetLastError()); - core_ = new Core(this); - return OK; -} - int UDPSocketWin::SetReceiveBufferSize(int32 size) { + DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(CalledOnValidThread()); int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&size), sizeof(size)); @@ -507,6 +503,7 @@ } int UDPSocketWin::SetSendBufferSize(int32 size) { + DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(CalledOnValidThread()); int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&size), sizeof(size)); @@ -527,18 +524,26 @@ return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE; } -void UDPSocketWin::AllowAddressReuse() { +int UDPSocketWin::AllowAddressReuse() { + DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); - socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; + BOOL true_value = TRUE; + int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast<const char*>(&true_value), + sizeof(true_value)); + return rv == 0 ? OK : MapSystemError(WSAGetLastError()); } -void UDPSocketWin::AllowBroadcast() { +int UDPSocketWin::SetBroadcast(bool broadcast) { + DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(CalledOnValidThread()); - DCHECK(!is_connected()); - socket_options_ |= SOCKET_OPTION_BROADCAST; + BOOL value = broadcast ? TRUE : FALSE; + int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, + reinterpret_cast<const char*>(&value), sizeof(value)); + return rv == 0 ? OK : MapSystemError(WSAGetLastError()); } void UDPSocketWin::DoReadCallback(int rv) { @@ -718,22 +723,7 @@ return ERR_IO_PENDING; } -int UDPSocketWin::SetSocketOptions() { - BOOL true_value = 1; - if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { - int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast<const char*>(&true_value), - sizeof(true_value)); - if (rv < 0) - return MapSystemError(WSAGetLastError()); - } - if (socket_options_ & SOCKET_OPTION_BROADCAST) { - int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, - reinterpret_cast<const char*>(&true_value), - sizeof(true_value)); - if (rv < 0) - return MapSystemError(WSAGetLastError()); - } +int UDPSocketWin::SetMulticastOptions() { if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { DWORD loop = 0; int protocol_level =
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h index bc97d56..6f0ec2c 100644 --- a/net/udp/udp_socket_win.h +++ b/net/udp/udp_socket_win.h
@@ -12,6 +12,7 @@ #include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "base/win/object_watcher.h" +#include "net/base/address_family.h" #include "net/base/completion_callback.h" #include "net/base/net_export.h" #include "net/base/rand_callback.h" @@ -30,22 +31,28 @@ const net::NetLog::Source& source); virtual ~UDPSocketWin(); - // Connect the socket to connect with a certain |address|. + // Opens the socket. + // Returns a net error code. + int Open(AddressFamily address_family); + + // Connects the socket to connect with a certain |address|. + // Should be called after Open(). // Returns a net error code. int Connect(const IPEndPoint& address); - // Bind the address/port for this socket to |address|. This is generally - // only used on a server. + // Binds the address/port for this socket to |address|. This is generally + // only used on a server. Should be called after Open(). // Returns a net error code. int Bind(const IPEndPoint& address); - // Close the socket. + // Closes the socket. + // TODO(rvargas, hidehiko): Disallow re-Open() after Close(). void Close(); - // Copy the remote udp address into |address| and return a network error code. + // Copies the remote udp address into |address| and returns a net error code. int GetPeerAddress(IPEndPoint* address) const; - // Copy the local udp address into |address| and return a network error code. + // Copies the local udp address into |address| and returns a net error code. // (similar to getsockname) int GetLocalAddress(IPEndPoint* address) const; @@ -53,17 +60,17 @@ // Multiple outstanding read requests are not supported. // Full duplex mode (reading and writing at the same time) is supported - // Read from the socket. + // Reads from the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - // Write to the socket. + // Writes to the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - // Read from a socket and receive sender address information. + // Reads from a socket and receive sender address information. // |buf| is the buffer to read data into. // |buf_len| is the maximum amount of data to read. // |address| is a buffer provided by the caller for receiving the sender @@ -81,7 +88,7 @@ IPEndPoint* address, const CompletionCallback& callback); - // Send to a socket with a particular destination. + // Sends to a socket with a particular destination. // |buf| is the buffer to send // |buf_len| is the number of bytes to send // |address| is the recipient address. @@ -95,57 +102,57 @@ const IPEndPoint& address, const CompletionCallback& callback); - // Set the receive buffer size (in bytes) for the socket. + // Sets the receive buffer size (in bytes) for the socket. // Returns a net error code. int SetReceiveBufferSize(int32 size); - // Set the send buffer size (in bytes) for the socket. + // Sets the send buffer size (in bytes) for the socket. // Returns a net error code. int SetSendBufferSize(int32 size); // Returns true if the socket is already connected or bound. - bool is_connected() const { return socket_ != INVALID_SOCKET; } + bool is_connected() const { return is_connected_; } const BoundNetLog& NetLog() const { return net_log_; } // Sets corresponding flags in |socket_options_| to allow the socket // to share the local address to which the socket will be bound with - // other processes. Should be called before Bind(). - void AllowAddressReuse(); + // other processes. Should be called between Open() and Bind(). + // Returns a net error code. + int AllowAddressReuse(); // Sets corresponding flags in |socket_options_| to allow sending - // and receiving packets to and from broadcast addresses. Should be - // called before Bind(). - void AllowBroadcast(); + // and receiving packets to and from broadcast addresses. + int SetBroadcast(bool broadcast); - // Join the multicast group. + // Joins the multicast group. // |group_address| is the group address to join, could be either // an IPv4 or IPv6 address. - // Return a network error code. + // Returns a net error code. int JoinGroup(const IPAddressNumber& group_address) const; - // Leave the multicast group. + // Leaves the multicast group. // |group_address| is the group address to leave, could be either // an IPv4 or IPv6 address. If the socket hasn't joined the group, // it will be ignored. // It's optional to leave the multicast group before destroying // the socket. It will be done by the OS. - // Return a network error code. + // Return a net error code. int LeaveGroup(const IPAddressNumber& group_address) const; - // Set interface to use for multicast. If |interface_index| set to 0, default - // interface is used. + // Sets interface to use for multicast. If |interface_index| set to 0, + // default interface is used. // Should be called before Bind(). - // Returns a network error code. + // Returns a net error code. int SetMulticastInterface(uint32 interface_index); - // Set the time-to-live option for UDP packets sent to the multicast + // Sets the time-to-live option for UDP packets sent to the multicast // group address. The default value of this option is 1. // Cannot be negative or more than 255. // Should be called before Bind(). int SetMulticastTimeToLive(int time_to_live); - // Set the loopback flag for UDP socket. If this flag is true, the host + // Sets the loopback flag for UDP socket. If this flag is true, the host // will receive packets sent to the joined group from itself. // The default value of this option is true. // Should be called before Bind(). @@ -160,7 +167,7 @@ // other applications on the same host. See MSDN: http://goo.gl/6vqbj int SetMulticastLoopbackMode(bool loopback); - // Set the differentiated services flags on outgoing packets. May not + // Sets the differentiated services flags on outgoing packets. May not // do anything on some platforms. int SetDiffServCodePoint(DiffServCodePoint dscp); @@ -169,9 +176,7 @@ private: enum SocketOptions { - SOCKET_OPTION_REUSE_ADDRESS = 1 << 0, - SOCKET_OPTION_BROADCAST = 1 << 1, - SOCKET_OPTION_MULTICAST_LOOP = 1 << 2 + SOCKET_OPTION_MULTICAST_LOOP = 1 << 0 }; class Core; @@ -187,9 +192,6 @@ void LogRead(int result, const char* bytes) const; void LogWrite(int result, const char* bytes, const IPEndPoint* address) const; - // Returns the OS error code (or 0 on success). - int CreateSocket(int addr_family); - // Same as SendTo(), except that address is passed by pointer // instead of by reference. It is called from Write() with |address| // set to NULL. @@ -204,7 +206,7 @@ // Applies |socket_options_| to |socket_|. Should be called before // Bind(). - int SetSocketOptions(); + int SetMulticastOptions(); int DoBind(const IPEndPoint& address); // Binds to a random port on |address|. int RandomBind(const IPAddressNumber& address); @@ -215,6 +217,7 @@ SOCKET socket_; int addr_family_; + bool is_connected_; // Bitwise-or'd combination of SocketOptions. Specifies the set of // options that should be applied to |socket_| before Bind(). @@ -223,7 +226,7 @@ // Multicast interface. uint32 multicast_interface_; - // Multicast socket options cached for SetSocketOption. + // Multicast socket options cached for SetMulticastOption. // Cannot be used after Bind(). int multicast_time_to_live_;
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index c61a14b..132a67d 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -768,9 +768,18 @@ return true; } + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequest::Read1")); + bool rv = job_->Read(dest, dest_size, bytes_read); // If rv is false, the status cannot be success. DCHECK(rv || status_.status() != URLRequestStatus::SUCCESS); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequest::Read2")); + if (rv && *bytes_read <= 0 && status_.is_success()) NotifyRequestCompleted(); return rv;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index b114ecc..099a319 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -10,7 +10,6 @@ #endif #include <algorithm> -#include <string> #include "base/basictypes.h" #include "base/bind.h" @@ -99,6 +98,7 @@ using base::ASCIIToUTF16; using base::Time; +using std::string; namespace net { @@ -5437,6 +5437,25 @@ } } +// Make sure an HTTP request using the "unsafe" port 443 fails. +// See: https://crbug.com/436451 +TEST_F(URLRequestTestHTTP, UnsafePort) { + TestDelegate d; + { + scoped_ptr<URLRequest> r(default_context_.CreateRequest( + GURL("http://www.google.com:443/"), DEFAULT_PRIORITY, &d, NULL)); + + r->Start(); + EXPECT_TRUE(r->is_pending()); + + base::RunLoop().Run(); + + EXPECT_FALSE(r->is_pending()); + EXPECT_EQ(URLRequestStatus::FAILED, r->status().status()); + EXPECT_EQ(ERR_UNSAFE_PORT, r->status().error()); + } +} + // Tests that redirection to an unsafe URL is allowed when it has been marked as // safe. TEST_F(URLRequestTestHTTP, UnsafeRedirectToWhitelistedUnsafeURL) {
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 83c4d8b..e654afb 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -282,9 +282,6 @@ "ext/google_logging.cc", "ext/image_operations.cc", "ext/image_operations.h", - "ext/lazy_pixel_ref.cc", - "ext/lazy_pixel_ref.h", - "ext/SkThread_chrome.cc", "ext/opacity_draw_filter.cc", "ext/opacity_draw_filter.h", "ext/pixel_ref_utils.cc", @@ -418,13 +415,6 @@ ] } - # Fixup Chrome sources. - if (is_posix) { - sources -= [ "ext/SkThread_chrome.cc" ] - } - if (is_win) { - sources -= [ "ext/SkThread_chrome.cc" ] - } if (is_android && (!enable_basic_printing && !enable_print_preview)) { sources -= [ "ext/skia_utils_base.cc" ] }
diff --git a/skia/README.chromium b/skia/README.chromium deleted file mode 100644 index 9deca56..0000000 --- a/skia/README.chromium +++ /dev/null
@@ -1,20 +0,0 @@ -This is a copy of the Skia source tree. In the original repository, the include -directories and the "corecg" directories are separated out. On top of - libs/graphics -> skia -we have the following mappings from source repository to our tree: - include/corecg -> skia/include/corecg - include/graphics -> skia/include - libs/corecg -> skia/corecg - -platform/* are our own files that provide extra functionality we need our -Skia to implement. - -DO NOT CHANGE THE SKIA FILES IN OUR TREE. These will be overwritten when we -sync to newer versions of Skia. The exception is platform/ - -THE EXCEPTION IS include/corecg/SkUserConfig.h which are the application's -definition of its options and environment. This file must be manually merged -with any changes in the Skia tree so that our options are preserved and we -also pick up any important changes they make. - - -- brettw@google.com, 28 December 2006
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc index 48a09d1..17e8390 100644 --- a/skia/ext/analysis_canvas.cc +++ b/skia/ext/analysis_canvas.cc
@@ -95,17 +95,6 @@ is_transparent_ = false; } -void AnalysisCanvas::clear(SkColor color) { - is_transparent_ = (!is_forced_not_transparent_ && SkColorGetA(color) == 0); - - if (!is_forced_not_solid_ && SkColorGetA(color) == 255) { - is_solid_color_ = true; - color_ = color; - } else { - is_solid_color_ = false; - } -} - void AnalysisCanvas::drawPaint(const SkPaint& paint) { SkRect rect; getClipBounds(&rect);
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h index abedcaf..105ff2c 100644 --- a/skia/ext/analysis_canvas.h +++ b/skia/ext/analysis_canvas.h
@@ -30,7 +30,6 @@ bool abortDrawing() override; // SkCanvas overrides. - void clear(SkColor) override; void drawPaint(const SkPaint& paint) override; void drawPoints(PointMode, size_t count,
diff --git a/skia/ext/lazy_pixel_ref.cc b/skia/ext/lazy_pixel_ref.cc deleted file mode 100644 index 6941871..0000000 --- a/skia/ext/lazy_pixel_ref.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/lazy_pixel_ref.h" - -namespace skia { - -LazyPixelRef::LazyPixelRef(const SkImageInfo& info) : SkPixelRef(info) { -} - -LazyPixelRef::~LazyPixelRef() { -} - -} // namespace skia
diff --git a/skia/ext/lazy_pixel_ref.h b/skia/ext/lazy_pixel_ref.h deleted file mode 100644 index 2335fdf..0000000 --- a/skia/ext/lazy_pixel_ref.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_LAZY_PIXEL_REF_H_ -#define SKIA_EXT_LAZY_PIXEL_REF_H_ - -#include "third_party/skia/include/core/SkPixelRef.h" -#include "third_party/skia/include/core/SkRect.h" - -namespace skia { - -// This class extends SkPixelRef to facilitate lazy image decoding on the impl -// thread. -class SK_API LazyPixelRef : public SkPixelRef { - public: - explicit LazyPixelRef(const SkImageInfo& info); - ~LazyPixelRef() override; - - struct PrepareParams { - // Clipping rect for this pixel ref. - SkIRect clip_rect; - }; - - // Request the ImageDecodingStore to prepare image decoding for the - // given clipping rect. Returns true is succeeded, or false otherwise. - virtual bool PrepareToDecode(const PrepareParams& params) = 0; - - // Returns true if this pixel ref is already in the ImageDecodingStore's - // cache, false otherwise. Much cheaper than PrepareToDecode(). - virtual bool MaybeDecoded() = 0; - - // Start decoding the image. - virtual void Decode() = 0; -}; - -} // namespace skia - -#endif // SKIA_EXT_LAZY_PIXEL_REF_H_
diff --git a/skia/ext/pixel_ref_utils.cc b/skia/ext/pixel_ref_utils.cc index 4e85f7a..324adbd 100644 --- a/skia/ext/pixel_ref_utils.cc +++ b/skia/ext/pixel_ref_utils.cc
@@ -51,7 +51,6 @@ DiscardablePixelRefSet* pixel_ref_set) : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {} - void clear(SkColor color) override {} void drawPaint(const SkDraw& draw, const SkPaint& paint) override { SkBitmap bitmap; if (GetBitmapFromPaint(paint, &bitmap)) {
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi index cff4e3c..6a24635 100644 --- a/skia/skia_chrome.gypi +++ b/skia/skia_chrome.gypi
@@ -52,8 +52,6 @@ 'ext/google_logging.cc', 'ext/image_operations.cc', 'ext/image_operations.h', - 'ext/lazy_pixel_ref.cc', - 'ext/lazy_pixel_ref.h', 'ext/opacity_draw_filter.cc', 'ext/opacity_draw_filter.h', 'ext/pixel_ref_utils.cc',
diff --git a/sky/engine/platform/graphics/Gradient.cpp b/sky/engine/platform/graphics/Gradient.cpp index ccd8505..e4abfe5 100644 --- a/sky/engine/platform/graphics/Gradient.cpp +++ b/sky/engine/platform/graphics/Gradient.cpp
@@ -32,7 +32,6 @@ #include "sky/engine/platform/graphics/GraphicsContext.h" #include "sky/engine/platform/graphics/skia/SkiaUtils.h" #include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkColorShader.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/effects/SkGradientShader.h" @@ -260,7 +259,7 @@ if (!m_gradient) { // use last color, since our "geometry" was degenerate (e.g. radius==0) - m_gradient = adoptRef(new SkColorShader(colors[countUsed - 1])); + m_gradient = adoptRef(SkShader::CreateColorShader(colors[countUsed - 1])); } return m_gradient.get(); }
diff --git a/sky/engine/platform/graphics/InterceptingCanvas.h b/sky/engine/platform/graphics/InterceptingCanvas.h index dbf9567..a3e9ba5 100644 --- a/sky/engine/platform/graphics/InterceptingCanvas.h +++ b/sky/engine/platform/graphics/InterceptingCanvas.h
@@ -40,7 +40,6 @@ InterceptingCanvas(SkBitmap bitmap) : SkCanvas(bitmap), m_depthCount(0) { }; InterceptingCanvas(int width, int height) : SkCanvas(width, height), m_depthCount(0) { }; - virtual void clear(SkColor) override = 0; virtual void drawPaint(const SkPaint&) override = 0; virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override = 0; virtual void drawRect(const SkRect&, const SkPaint&) override = 0;
diff --git a/sky/engine/platform/graphics/LoggingCanvas.cpp b/sky/engine/platform/graphics/LoggingCanvas.cpp index 892b26d..18adab9 100644 --- a/sky/engine/platform/graphics/LoggingCanvas.cpp +++ b/sky/engine/platform/graphics/LoggingCanvas.cpp
@@ -84,13 +84,6 @@ m_log = JSONArray::create(); } -void LoggingCanvas::clear(SkColor color) -{ - AutoLogger logger(this); - logger.logItemWithParams("clear")->setString("color", stringForSkColor(color)); - this->SkCanvas::clear(color); -} - void LoggingCanvas::drawPaint(const SkPaint& paint) { AutoLogger logger(this);
diff --git a/sky/engine/platform/graphics/LoggingCanvas.h b/sky/engine/platform/graphics/LoggingCanvas.h index b2a833b..3483015 100644 --- a/sky/engine/platform/graphics/LoggingCanvas.h +++ b/sky/engine/platform/graphics/LoggingCanvas.h
@@ -41,7 +41,6 @@ LoggingCanvas(int width, int height); PassRefPtr<JSONArray> log(); - virtual void clear(SkColor) override; virtual void drawPaint(const SkPaint&) override; virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/sky/engine/platform/graphics/Pattern.cpp b/sky/engine/platform/graphics/Pattern.cpp index d29593f..3bd1112 100644 --- a/sky/engine/platform/graphics/Pattern.cpp +++ b/sky/engine/platform/graphics/Pattern.cpp
@@ -30,7 +30,6 @@ #include "sky/engine/platform/graphics/skia/SkiaUtils.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColorShader.h" #include "v8/include/v8.h" namespace blink { @@ -64,7 +63,7 @@ // If we don't have a bitmap, return a transparent shader. if (!m_tileImage) { - m_pattern = adoptRef(new SkColorShader(SK_ColorTRANSPARENT)); + m_pattern = adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); } else if (m_repeatMode == RepeatModeXY) { m_pattern = adoptRef(SkShader::CreateBitmapShader(m_tileImage->bitmap(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.cpp b/sky/engine/platform/graphics/ProfilingCanvas.cpp index 6faaa91..2940339 100644 --- a/sky/engine/platform/graphics/ProfilingCanvas.cpp +++ b/sky/engine/platform/graphics/ProfilingCanvas.cpp
@@ -69,12 +69,6 @@ m_timings = timings; } -void ProfilingCanvas::clear(SkColor color) -{ - AutoStamper stamper(this); - this->SkCanvas::clear(color); -} - void ProfilingCanvas::drawPaint(const SkPaint& paint) { AutoStamper stamper(this);
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.h b/sky/engine/platform/graphics/ProfilingCanvas.h index 007f842..b390ab4 100644 --- a/sky/engine/platform/graphics/ProfilingCanvas.h +++ b/sky/engine/platform/graphics/ProfilingCanvas.h
@@ -41,7 +41,6 @@ ProfilingCanvas(SkBitmap); void setTimings(Vector<double>*); - virtual void clear(SkColor) override; virtual void drawPaint(const SkPaint&) override; virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.cpp b/sky/engine/platform/graphics/ReplayingCanvas.cpp index db2433a..3c13a10 100644 --- a/sky/engine/platform/graphics/ReplayingCanvas.cpp +++ b/sky/engine/platform/graphics/ReplayingCanvas.cpp
@@ -83,12 +83,6 @@ return m_abortDrawing; } -void ReplayingCanvas::clear(SkColor color) -{ - AutoReplayer replayer(this); - this->SkCanvas::clear(color); -} - void ReplayingCanvas::drawPaint(const SkPaint& paint) { AutoReplayer replayer(this);
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.h b/sky/engine/platform/graphics/ReplayingCanvas.h index 99ca93a..a8e9541 100644 --- a/sky/engine/platform/graphics/ReplayingCanvas.h +++ b/sky/engine/platform/graphics/ReplayingCanvas.h
@@ -43,7 +43,6 @@ virtual bool abortDrawing() override; - virtual void clear(SkColor) override; virtual void drawPaint(const SkPaint&) override; virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; virtual void drawRect(const SkRect&, const SkPaint&) override;
diff --git a/third_party/protobuf/OWNERS b/third_party/protobuf/OWNERS new file mode 100644 index 0000000..a0b277d --- /dev/null +++ b/third_party/protobuf/OWNERS
@@ -0,0 +1,2 @@ +agl@chromium.org +scottmg@chromium.org
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index 6fff4cb..14e3052 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py
@@ -326,12 +326,8 @@ 'names': ['glDisableVertexAttribArray'], 'arguments': 'GLuint index', }, { 'return_type': 'void', - 'known_as': 'glDiscardFramebufferEXT', - 'versions': [{ 'name': 'glInvalidateFramebuffer', - 'gl_versions': ['es3'], - 'extensions': [] }, - { 'name': 'glDiscardFramebufferEXT', - 'gl_versions': ['es1', 'es2'] }], + 'versions': [{ 'name': 'glDiscardFramebufferEXT', + 'extensions': ['GL_EXT_discard_framebuffer'] }], 'arguments': 'GLenum target, GLsizei numAttachments, ' 'const GLenum* attachments' }, { 'return_type': 'void', @@ -698,6 +694,11 @@ 'names': ['glInsertEventMarkerEXT'], 'arguments': 'GLsizei length, const char* marker', }, { 'return_type': 'void', + 'versions': [{ 'name': 'glInvalidateFramebuffer', + 'gl_versions': ['gl4', 'es3'] }], # GL 4.3 or higher. + 'arguments': 'GLenum target, GLsizei numAttachments, ' + 'const GLenum* attachments' }, +{ 'return_type': 'void', 'versions': [{ 'name': 'glInvalidateSubFramebuffer', 'gl_versions': ['gl4', 'es3'] }], # GL 4.3 or higher. 'arguments':
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index 0d25bbe..86f921b 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h
@@ -100,9 +100,13 @@ #define GL_LUMINANCE_ALPHA32F_EXT 0x8819 #define GL_RGBA16F_EXT 0x881A #define GL_RGB16F_EXT 0x881B +#define GL_RG16F_EXT 0x822F +#define GL_R16F_EXT 0x822D #define GL_ALPHA16F_EXT 0x881C #define GL_LUMINANCE16F_EXT 0x881E #define GL_LUMINANCE_ALPHA16F_EXT 0x881F +#define GL_R32F_EXT 0x822E +#define GL_RG32F_EXT 0x8230 #define GL_BGRA8_EXT 0x93A1 // GL_ANGLE_instanced_arrays
diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc index 2d91a65..7f9cf2d 100644 --- a/ui/gl/gl_context_android.cc +++ b/ui/gl/gl_context_android.cc
@@ -120,7 +120,7 @@ // Droid Razr M(1GB) 114MB (normally 57MB) // Galaxy Nexus(1GB) 100MB (normally 50MB) // Xoom(1GB) 100MB (normally 50MB) - // Nexus S(low-end) 12MB (normally 8MB) + // Nexus S(low-end) 8MB (normally 8MB) // Note that the compositor now uses only some of this memory for // pre-painting and uses the rest only for 'emergencies'. static size_t limit_bytes = 0; @@ -140,9 +140,7 @@ // Low-end devices have 512MB or less memory by definition // so we hard code the limit rather than relying on the heuristics // above. Low-end devices use 4444 textures so we can use a lower limit. - // NOTE: Low-end uses 2/3 (67%) of this memory in practice, so we have - // increased the limit to 12 (8MB, or 12MB in emergencies). - limit_bytes = 12; + limit_bytes = 8; } limit_bytes = limit_bytes * 1024 * 1024; }
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc index 017e123..7f6a647 100644 --- a/ui/gl/gl_gl_api_implementation.cc +++ b/ui/gl/gl_gl_api_implementation.cc
@@ -48,6 +48,42 @@ // g_version_info must be initialized when this function is bound. DCHECK(gfx::g_version_info); + if (gfx::g_version_info->is_es3) { + if (format == GL_RED_EXT) { + switch (type) { + case GL_UNSIGNED_BYTE: + gl_internal_format = GL_R8_EXT; + break; + case GL_HALF_FLOAT_OES: + gl_internal_format = GL_R16F_EXT; + break; + case GL_FLOAT: + gl_internal_format = GL_R32F_EXT; + break; + default: + NOTREACHED(); + break; + } + return gl_internal_format; + } else if (format == GL_RG_EXT) { + switch (type) { + case GL_UNSIGNED_BYTE: + gl_internal_format = GL_RG8_EXT; + break; + case GL_HALF_FLOAT_OES: + gl_internal_format = GL_RG16F_EXT; + break; + case GL_FLOAT: + gl_internal_format = GL_RG32F_EXT; + break; + default: + NOTREACHED(); + break; + } + return gl_internal_format; + } + } + if (type == GL_FLOAT && gfx::g_version_info->is_angle && gfx::g_version_info->is_es2) { // It's possible that the texture is using a sized internal format, and
diff --git a/ui/gl/gl_version_info.h b/ui/gl/gl_version_info.h index 13b323f..21ca07a 100644 --- a/ui/gl/gl_version_info.h +++ b/ui/gl/gl_version_info.h
@@ -7,10 +7,11 @@ #include <string> #include "base/basictypes.h" +#include "ui/gl/gl_export.h" namespace gfx { -struct GLVersionInfo { +struct GL_EXPORT GLVersionInfo { GLVersionInfo(const char* version_str, const char* renderer_str); // New flags, such as is_gl4_4 could be introduced as needed. @@ -27,7 +28,7 @@ bool is_angle; -private: + private: DISALLOW_COPY_AND_ASSIGN(GLVersionInfo); };
diff --git a/ui/gl/gpu_switching_manager.cc b/ui/gl/gpu_switching_manager.cc index f904629..020592f 100644 --- a/ui/gl/gpu_switching_manager.cc +++ b/ui/gl/gpu_switching_manager.cc
@@ -9,12 +9,19 @@ #include "ui/gl/gl_switches.h" #if defined(OS_MACOSX) +#include <OpenGL/OpenGL.h> #include "base/mac/mac_util.h" #include "ui/gl/gl_context_cgl.h" #endif // OS_MACOSX namespace ui { +struct GpuSwitchingManager::PlatformSpecific { +#if defined(OS_MACOSX) + CGLPixelFormatObj discrete_pixel_format; +#endif // OS_MACOSX +}; + // static GpuSwitchingManager* GpuSwitchingManager::GetInstance() { return Singleton<GpuSwitchingManager>::get(); @@ -25,16 +32,17 @@ gpu_switching_option_set_(false), supports_dual_gpus_(false), supports_dual_gpus_set_(false), - gpu_count_(0) { + gpu_count_(0), + platform_specific_(new PlatformSpecific) { #if defined(OS_MACOSX) - discrete_pixel_format_ = NULL; + platform_specific_->discrete_pixel_format = nullptr; #endif // OS_MACOSX } GpuSwitchingManager::~GpuSwitchingManager() { #if defined(OS_MACOSX) - if (discrete_pixel_format_) - CGLReleasePixelFormat(discrete_pixel_format_); + if (platform_specific_->discrete_pixel_format) + CGLReleasePixelFormat(platform_specific_->discrete_pixel_format); #endif // OS_MACOSX } @@ -123,12 +131,13 @@ #if defined(OS_MACOSX) void GpuSwitchingManager::SwitchToDiscreteGpuMac() { - if (discrete_pixel_format_) + if (platform_specific_->discrete_pixel_format) return; CGLPixelFormatAttribute attribs[1]; attribs[0] = static_cast<CGLPixelFormatAttribute>(0); GLint num_pixel_formats = 0; - CGLChoosePixelFormat(attribs, &discrete_pixel_format_, &num_pixel_formats); + CGLChoosePixelFormat(attribs, &platform_specific_->discrete_pixel_format, + &num_pixel_formats); } #endif // OS_MACOSX
diff --git a/ui/gl/gpu_switching_manager.h b/ui/gl/gpu_switching_manager.h index 7e82d62..a6a810f 100644 --- a/ui/gl/gpu_switching_manager.h +++ b/ui/gl/gpu_switching_manager.h
@@ -13,10 +13,6 @@ #include "ui/gl/gpu_preference.h" #include "ui/gl/gpu_switching_observer.h" -#if defined(OS_MACOSX) -#include <OpenGL/OpenGL.h> -#endif // OS_MACOSX - namespace ui { class GL_EXPORT GpuSwitchingManager { @@ -60,8 +56,6 @@ #if defined(OS_MACOSX) void SwitchToDiscreteGpuMac(); - - CGLPixelFormatObj discrete_pixel_format_; #endif // OS_MACOSX gfx::GpuPreference gpu_switching_option_; @@ -72,6 +66,9 @@ size_t gpu_count_; + struct PlatformSpecific; + scoped_ptr<PlatformSpecific> platform_specific_; + ObserverList<GpuSwitchingObserver> observer_list_; DISALLOW_COPY_AND_ASSIGN(GpuSwitchingManager);
diff --git a/url/gurl.cc b/url/gurl.cc index b580125..46ca408 100644 --- a/url/gurl.cc +++ b/url/gurl.cc
@@ -177,6 +177,22 @@ return EmptyStringForGURL(); } +bool GURL::operator==(const GURL& other) const { + return spec_ == other.spec_; +} + +bool GURL::operator!=(const GURL& other) const { + return spec_ != other.spec_; +} + +bool GURL::operator<(const GURL& other) const { + return spec_ < other.spec_; +} + +bool GURL::operator>(const GURL& other) const { + return spec_ > other.spec_; +} + GURL GURL::Resolve(const std::string& relative) const { return ResolveWithCharsetConverter(relative, NULL); }
diff --git a/url/gurl.h b/url/gurl.h index f370934..ef1e529 100644 --- a/url/gurl.h +++ b/url/gurl.h
@@ -112,20 +112,12 @@ } // Defiant equality operator! - bool operator==(const GURL& other) const { - return spec_ == other.spec_; - } - bool operator!=(const GURL& other) const { - return spec_ != other.spec_; - } + bool operator==(const GURL& other) const; + bool operator!=(const GURL& other) const; // Allows GURL to used as a key in STL (for example, a std::set or std::map). - bool operator<(const GURL& other) const { - return spec_ < other.spec_; - } - bool operator>(const GURL& other) const { - return spec_ > other.spec_; - } + bool operator<(const GURL& other) const; + bool operator>(const GURL& other) const; // Resolves a URL that's possibly relative to this object's URL, and returns // it. Absolute URLs are also handled according to the rules of URLs on web